from bokeh.resources import INLINE
import bokeh.io
from bokeh import *
bokeh.io.output_notebook(INLINE)
Introducción a la visualización de datos con Python¶
La visualización de datos es el arte y la ciencia de contar historias cautivadoras con datos.
¿Por qué Python?
Python realiza cálculos numéricos y científicos avanzados con librerías como: numpy y scipy, alberga una amplia gama de métodos de de métodos de aprendizaje automático gracias a la disponibilidad del paquete scikit-learn
Proporciona una gran interfaz para manipulación de big data gracias a la disponibilidad del paquete
pandasy su compatibilidad con Apache SparkGenera gráficos y figuras estéticamente con librerías como seaborn, plotly, etc.
Manejo de datos con pandas DataFrame¶
La biblioteca pandas es un conjunto de herramientas de código abierto extremadamente ingenioso para manejar manipular y analizar datos estructurados. Las tablas de datos se pueden almacenar en el objeto DataFrame disponible en pandas, y los datos en múltiples formatos (por ejemplo, .csv, .tsv, .xlsx y .json) pueden leerse directamente en un DataFrame.
Ejercicio 1: Lectura de datos desde archivos¶
En este ejercicio, leeremos de un conjunto de datos. En este ejemplo se utiliza el conjunto de datos diamantes
Abre un cuaderno jupyter y carga la librería pandas
import pandas as pd
import warnings
warnings.filterwarnings('ignore')
Especifique la URL del conjunto de datos:
diamonds_url = "https://raw.githubusercontent.com/lihkir/Uninorte/main/AppliedStatisticMS/DataVisualizationRPython/Lectures/Python/PythonDataSets/diamonds.csv"
Leer los archivos de la URL en el DataFrame de pandas
diamonds_df = pd.read_csv(diamonds_url)
diamonds_df.head()
| carat | cut | color | clarity | depth | table | price | x | y | z | |
|---|---|---|---|---|---|---|---|---|---|---|
| 0 | 0.23 | Ideal | E | SI2 | 61.5 | 55.0 | 326 | 3.95 | 3.98 | 2.43 |
| 1 | 0.21 | Premium | E | SI1 | 59.8 | 61.0 | 326 | 3.89 | 3.84 | 2.31 |
| 2 | 0.23 | Good | E | VS1 | 56.9 | 65.0 | 327 | 4.05 | 4.07 | 2.31 |
| 3 | 0.29 | Premium | I | VS2 | 62.4 | 58.0 | 334 | 4.20 | 4.23 | 2.63 |
| 4 | 0.31 | Good | J | SI2 | 63.3 | 58.0 | 335 | 4.34 | 4.35 | 2.75 |
Use the usecols parameter if only specific columns need to be read.
diamonds_df_specific_cols = pd.read_csv(diamonds_url, usecols=['carat','cut','color','clarity'])
diamonds_df_specific_cols.head()
| carat | cut | color | clarity | |
|---|---|---|---|---|
| 0 | 0.23 | Ideal | E | SI2 |
| 1 | 0.21 | Premium | E | SI1 |
| 2 | 0.23 | Good | E | VS1 |
| 3 | 0.29 | Premium | I | VS2 |
| 4 | 0.31 | Good | J | SI2 |
Ejercicio 2: Observación y descripción de datos¶
En este ejercicio, veremos cómo observar y describir datos en un DataFrame. Volveremos a utilizar el conjunto de datos de diamantes
Cargue la librería pandas:
import pandas as pd
Leer los archivos de la URL en el DataFrame de pandas
diamonds_df = pd.read_csv(diamonds_url)
Observe los datos utilizando la función head:
diamonds_df.head()
| carat | cut | color | clarity | depth | table | price | x | y | z | |
|---|---|---|---|---|---|---|---|---|---|---|
| 0 | 0.23 | Ideal | E | SI2 | 61.5 | 55.0 | 326 | 3.95 | 3.98 | 2.43 |
| 1 | 0.21 | Premium | E | SI1 | 59.8 | 61.0 | 326 | 3.89 | 3.84 | 2.31 |
| 2 | 0.23 | Good | E | VS1 | 56.9 | 65.0 | 327 | 4.05 | 4.07 | 2.31 |
| 3 | 0.29 | Premium | I | VS2 | 62.4 | 58.0 | 334 | 4.20 | 4.23 | 2.63 |
| 4 | 0.31 | Good | J | SI2 | 63.3 | 58.0 | 335 | 4.34 | 4.35 | 2.75 |
Los datos contienen diferentes características de los diamantes, como quilates, calidad de corte, color y precio: carat, cut, color, clarity, depth, table, price como columnas. Ahora, corte, claridad y color son variables categóricas, y x, y, z, profundidad, tabla y precio son variables continuas. Mientras que las variables categóricas toman como valores categorías/nombres únicos, los valores continuos toman números reales como valores.
Contar el número de filas y columnas en el DataFrame utilizando la función shape
diamonds_df.shape
(53940, 10)
Resumir las columnas utilizando
describe()para obtener la distribución de las variables, incluyendo la media, la mediana, el mínimo, el máximo y los diferentes cuartiles
diamonds_df.describe()
| carat | depth | table | price | x | y | z | |
|---|---|---|---|---|---|---|---|
| count | 53940.000000 | 53940.000000 | 53940.000000 | 53940.000000 | 53940.000000 | 53940.000000 | 53940.000000 |
| mean | 0.797940 | 61.749405 | 57.457184 | 3932.799722 | 5.731157 | 5.734526 | 3.538734 |
| std | 0.474011 | 1.432621 | 2.234491 | 3989.439738 | 1.121761 | 1.142135 | 0.705699 |
| min | 0.200000 | 43.000000 | 43.000000 | 326.000000 | 0.000000 | 0.000000 | 0.000000 |
| 25% | 0.400000 | 61.000000 | 56.000000 | 950.000000 | 4.710000 | 4.720000 | 2.910000 |
| 50% | 0.700000 | 61.800000 | 57.000000 | 2401.000000 | 5.700000 | 5.710000 | 3.530000 |
| 75% | 1.040000 | 62.500000 | 59.000000 | 5324.250000 | 6.540000 | 6.540000 | 4.040000 |
| max | 5.010000 | 79.000000 | 95.000000 | 18823.000000 | 10.740000 | 58.900000 | 31.800000 |
Esto funciona para las variables continuas. Sin embargo, para las variables categóricas, necesitamos utilizar el parámetro include=object.
diamonds_df.describe(include=object)
| cut | color | clarity | |
|---|---|---|---|
| count | 53940 | 53940 | 53940 |
| unique | 5 | 7 | 8 |
| top | Ideal | G | SI1 |
| freq | 21551 | 11292 | 13065 |
Para obtener información sobre el conjunto de datos, utilice el método
info():
diamonds_df.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 53940 entries, 0 to 53939
Data columns (total 10 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 carat 53940 non-null float64
1 cut 53940 non-null object
2 color 53940 non-null object
3 clarity 53940 non-null object
4 depth 53940 non-null float64
5 table 53940 non-null float64
6 price 53940 non-null int64
7 x 53940 non-null float64
8 y 53940 non-null float64
9 z 53940 non-null float64
dtypes: float64(6), int64(1), object(3)
memory usage: 4.1+ MB
Podemos acceder a la columna corte del DataFrame diamonds_df con diamonds_df.cut o diamonds_df[‘cut’]
Ahora, ¿qué tal si seleccionamos todas las filas correspondientes a los diamantes que tienen la talla Ideal y almacenarlas en un DataFrame separado? Podemos seleccionarlas utilizando la función loc para seleccionarlos:
diamonds_low_df = diamonds_df.loc[diamonds_df['cut']=='Ideal']
diamonds_low_df.head()
| carat | cut | color | clarity | depth | table | price | x | y | z | |
|---|---|---|---|---|---|---|---|---|---|---|
| 0 | 0.23 | Ideal | E | SI2 | 61.5 | 55.0 | 326 | 3.95 | 3.98 | 2.43 |
| 11 | 0.23 | Ideal | J | VS1 | 62.8 | 56.0 | 340 | 3.93 | 3.90 | 2.46 |
| 13 | 0.31 | Ideal | J | SI2 | 62.2 | 54.0 | 344 | 4.35 | 4.37 | 2.71 |
| 16 | 0.30 | Ideal | I | SI2 | 62.0 | 54.0 | 348 | 4.31 | 4.34 | 2.68 |
| 39 | 0.33 | Ideal | I | SI2 | 61.8 | 55.0 | 403 | 4.49 | 4.51 | 2.78 |
Ejercicio 3: Añadir nuevas columnas al DataFrame¶
En este ejercicio, vamos a añadir nuevas columnas al conjunto de datos de diamantes en la biblioteca pandas. Empezaremos con la adición simple de columnas y luego avanzaremos y veremos la adición condicional de columnas. Para ello, vamos a seguir los siguientes pasos:
Cargue la biblioteca
pandas
import pandas as pd
Leer los archivos de la URL en el DataFrame de pandas
diamonds_df = pd.read_csv(diamonds_url)
diamonds_df.head()
| carat | cut | color | clarity | depth | table | price | x | y | z | |
|---|---|---|---|---|---|---|---|---|---|---|
| 0 | 0.23 | Ideal | E | SI2 | 61.5 | 55.0 | 326 | 3.95 | 3.98 | 2.43 |
| 1 | 0.21 | Premium | E | SI1 | 59.8 | 61.0 | 326 | 3.89 | 3.84 | 2.31 |
| 2 | 0.23 | Good | E | VS1 | 56.9 | 65.0 | 327 | 4.05 | 4.07 | 2.31 |
| 3 | 0.29 | Premium | I | VS2 | 62.4 | 58.0 | 334 | 4.20 | 4.23 | 2.63 |
| 4 | 0.31 | Good | J | SI2 | 63.3 | 58.0 | 335 | 4.34 | 4.35 | 2.75 |
Añade una columna
price_per_caratalDataFrame. En este ejemplo el precio por quilates. Del mismo modo, también podemos utilizar la suma, la resta y otros operadores matemáticos sobre dos columnas numéricas.
diamonds_df['price_per_carat'] = diamonds_df['price']/diamonds_df['carat']
Llame a la función head de DataFrame para comprobar si la nueva columna se ha añadido como como se esperaba:
diamonds_df.head()
| carat | cut | color | clarity | depth | table | price | x | y | z | price_per_carat | |
|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | 0.23 | Ideal | E | SI2 | 61.5 | 55.0 | 326 | 3.95 | 3.98 | 2.43 | 1417.391304 |
| 1 | 0.21 | Premium | E | SI1 | 59.8 | 61.0 | 326 | 3.89 | 3.84 | 2.31 | 1552.380952 |
| 2 | 0.23 | Good | E | VS1 | 56.9 | 65.0 | 327 | 4.05 | 4.07 | 2.31 | 1421.739130 |
| 3 | 0.29 | Premium | I | VS2 | 62.4 | 58.0 | 334 | 4.20 | 4.23 | 2.63 | 1151.724138 |
| 4 | 0.31 | Good | J | SI2 | 63.3 | 58.0 | 335 | 4.34 | 4.35 | 2.75 | 1080.645161 |
Ahora, veremos la adición condicional de columnas. Vamos a intentar añadir una columna basada en el valor de
price_per_carat, digamos que todo lo que sea más de 3500 como alto (codificado como 1) y todo lo que sea inferior a 3500 como bajo (codificado como 0).
import numpy as np
diamonds_df['price_per_carat_is_high'] = np.where(diamonds_df['price_per_carat'] > 3500, 1, 0)
diamonds_df.tail()
| carat | cut | color | clarity | depth | table | price | x | y | z | price_per_carat | price_per_carat_is_high | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 53935 | 0.72 | Ideal | D | SI1 | 60.8 | 57.0 | 2757 | 5.75 | 5.76 | 3.50 | 3829.166667 | 1 |
| 53936 | 0.72 | Good | D | SI1 | 63.1 | 55.0 | 2757 | 5.69 | 5.75 | 3.61 | 3829.166667 | 1 |
| 53937 | 0.70 | Very Good | D | SI1 | 62.8 | 60.0 | 2757 | 5.66 | 5.68 | 3.56 | 3938.571429 | 1 |
| 53938 | 0.86 | Premium | H | SI2 | 61.0 | 58.0 | 2757 | 6.15 | 6.12 | 3.74 | 3205.813953 | 0 |
| 53939 | 0.75 | Ideal | D | SI2 | 62.2 | 55.0 | 2757 | 5.83 | 5.87 | 3.64 | 3676.000000 | 1 |
Ejercicio 4: Aplicación de funciones a las columnas de DataFrame¶
En este ejercicio, consideraremos un escenario en el que el precio de los diamantes ha aumentado y queremos aplicar un factor de incremento de 1.3 al precio de todos los diamantes en nuestro registro. Podemos conseguirlo aplicando una sencilla función. A continuación, redondearemos el precio de los diamantes hasta su tope. Para ello, vamos a seguir los siguientes pasos
Cargue la biblioteca
pandas
import pandas as pd
Leer los archivos de la URL en el DataFrame de pandas
diamonds_df = pd.read_csv(diamonds_url)
diamonds_df.head()
| carat | cut | color | clarity | depth | table | price | x | y | z | |
|---|---|---|---|---|---|---|---|---|---|---|
| 0 | 0.23 | Ideal | E | SI2 | 61.5 | 55.0 | 326 | 3.95 | 3.98 | 2.43 |
| 1 | 0.21 | Premium | E | SI1 | 59.8 | 61.0 | 326 | 3.89 | 3.84 | 2.31 |
| 2 | 0.23 | Good | E | VS1 | 56.9 | 65.0 | 327 | 4.05 | 4.07 | 2.31 |
| 3 | 0.29 | Premium | I | VS2 | 62.4 | 58.0 | 334 | 4.20 | 4.23 | 2.63 |
| 4 | 0.31 | Good | J | SI2 | 63.3 | 58.0 | 335 | 4.34 | 4.35 | 2.75 |
Aplique una función simple en las columnas utilizando el siguiente código:
diamonds_df['price'] = diamonds_df['price']*1.3
diamonds_df.head()
| carat | cut | color | clarity | depth | table | price | x | y | z | |
|---|---|---|---|---|---|---|---|---|---|---|
| 0 | 0.23 | Ideal | E | SI2 | 61.5 | 55.0 | 423.8 | 3.95 | 3.98 | 2.43 |
| 1 | 0.21 | Premium | E | SI1 | 59.8 | 61.0 | 423.8 | 3.89 | 3.84 | 2.31 |
| 2 | 0.23 | Good | E | VS1 | 56.9 | 65.0 | 425.1 | 4.05 | 4.07 | 2.31 |
| 3 | 0.29 | Premium | I | VS2 | 62.4 | 58.0 | 434.2 | 4.20 | 4.23 | 2.63 |
| 4 | 0.31 | Good | J | SI2 | 63.3 | 58.0 | 435.5 | 4.34 | 4.35 | 2.75 |
Aplicar la función
math.ceilpara redondear el precio de los diamantes hasta su tope
import math
diamonds_df['rounded_price'] = diamonds_df['price'].apply(math.ceil)
diamonds_df.head()
| carat | cut | color | clarity | depth | table | price | x | y | z | rounded_price | |
|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | 0.23 | Ideal | E | SI2 | 61.5 | 55.0 | 423.8 | 3.95 | 3.98 | 2.43 | 424 |
| 1 | 0.21 | Premium | E | SI1 | 59.8 | 61.0 | 423.8 | 3.89 | 3.84 | 2.31 | 424 |
| 2 | 0.23 | Good | E | VS1 | 56.9 | 65.0 | 425.1 | 4.05 | 4.07 | 2.31 | 426 |
| 3 | 0.29 | Premium | I | VS2 | 62.4 | 58.0 | 434.2 | 4.20 | 4.23 | 2.63 | 435 |
| 4 | 0.31 | Good | J | SI2 | 63.3 | 58.0 | 435.5 | 4.34 | 4.35 | 2.75 | 436 |
Puede haber ocasiones en las que tenga que escribir su propia función para realizar la tarea que desea llevar a cabo.
Por ejemplo, digamos que quiere añadir otra columna al DataFrame indicando el precio redondeado de los diamantes al múltiplo de 100 (igual o superior al precio).
Utilice la función
lambdacomo sigue para redondear el precio de los diamantes al múltiplo de 100 más cercano
import math
diamonds_df['rounded_price_to_100multiple'] = diamonds_df['price'].apply(lambda x: 100*math.ceil(x/100))
diamonds_df.head()
| carat | cut | color | clarity | depth | table | price | x | y | z | rounded_price | rounded_price_to_100multiple | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | 0.23 | Ideal | E | SI2 | 61.5 | 55.0 | 423.8 | 3.95 | 3.98 | 2.43 | 424 | 500 |
| 1 | 0.21 | Premium | E | SI1 | 59.8 | 61.0 | 423.8 | 3.89 | 3.84 | 2.31 | 424 | 500 |
| 2 | 0.23 | Good | E | VS1 | 56.9 | 65.0 | 425.1 | 4.05 | 4.07 | 2.31 | 426 | 500 |
| 3 | 0.29 | Premium | I | VS2 | 62.4 | 58.0 | 434.2 | 4.20 | 4.23 | 2.63 | 435 | 500 |
| 4 | 0.31 | Good | J | SI2 | 63.3 | 58.0 | 435.5 | 4.34 | 4.35 | 2.75 | 436 | 500 |
Por supuesto, no todas las funciones pueden ser escritas en una sola línea y es importante saber cómo incluir funciones definidas por el usuario en la función
apply. Vamos a escribir el mismo código con una función definida por el usuario para ilustrarlo.
import math
def get_100_multiple_ceil(x):
y = 100*math.ceil(x/100)
return y
diamonds_df['rounded_price_to_100multiple']=diamonds_df['price'].apply(get_100_multiple_ceil)
diamonds_df.head()
| carat | cut | color | clarity | depth | table | price | x | y | z | rounded_price | rounded_price_to_100multiple | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | 0.23 | Ideal | E | SI2 | 61.5 | 55.0 | 423.8 | 3.95 | 3.98 | 2.43 | 424 | 500 |
| 1 | 0.21 | Premium | E | SI1 | 59.8 | 61.0 | 423.8 | 3.89 | 3.84 | 2.31 | 424 | 500 |
| 2 | 0.23 | Good | E | VS1 | 56.9 | 65.0 | 425.1 | 4.05 | 4.07 | 2.31 | 426 | 500 |
| 3 | 0.29 | Premium | I | VS2 | 62.4 | 58.0 | 434.2 | 4.20 | 4.23 | 2.63 | 435 | 500 |
| 4 | 0.31 | Good | J | SI2 | 63.3 | 58.0 | 435.5 | 4.34 | 4.35 | 2.75 | 436 | 500 |
Ejercicio 5: Aplicación de funciones en varias columnas¶
Supongamos que estamos interesados en comprar diamantes que tengan Ideal cut y color D (totalmente incoloro). Este ejercicio consiste en añadir una nueva columna, desired, al DataFrame, cuyo valor será yes si se cumplen nuestros criterios y no si no se cumplen. Veamos cómo lo hacemos:
Cargue la biblioteca pandas
import pandas as pd
Leer los archivos de la URL en el DataFrame de pandas
diamonds_df_exercise = pd.read_csv(diamonds_url)
diamonds_df_exercise.head()
| carat | cut | color | clarity | depth | table | price | x | y | z | |
|---|---|---|---|---|---|---|---|---|---|---|
| 0 | 0.23 | Ideal | E | SI2 | 61.5 | 55.0 | 326 | 3.95 | 3.98 | 2.43 |
| 1 | 0.21 | Premium | E | SI1 | 59.8 | 61.0 | 326 | 3.89 | 3.84 | 2.31 |
| 2 | 0.23 | Good | E | VS1 | 56.9 | 65.0 | 327 | 4.05 | 4.07 | 2.31 |
| 3 | 0.29 | Premium | I | VS2 | 62.4 | 58.0 | 334 | 4.20 | 4.23 | 2.63 |
| 4 | 0.31 | Good | J | SI2 | 63.3 | 58.0 | 335 | 4.34 | 4.35 | 2.75 |
Write a function to determine whether a record, x, is desired or not:
def is_desired(x):
bool_var = 'yes' if (x['cut']=='Ideal' and x['color']=='D') else 'no'
return bool_var
Utilice la función
applypara añadir la nueva columna, desired:
diamonds_df_exercise['desired'] = diamonds_df_exercise.apply(is_desired, axis = 'columns')
diamonds_df_exercise.tail()
| carat | cut | color | clarity | depth | table | price | x | y | z | desired | |
|---|---|---|---|---|---|---|---|---|---|---|---|
| 53935 | 0.72 | Ideal | D | SI1 | 60.8 | 57.0 | 2757 | 5.75 | 5.76 | 3.50 | yes |
| 53936 | 0.72 | Good | D | SI1 | 63.1 | 55.0 | 2757 | 5.69 | 5.75 | 3.61 | no |
| 53937 | 0.70 | Very Good | D | SI1 | 62.8 | 60.0 | 2757 | 5.66 | 5.68 | 3.56 | no |
| 53938 | 0.86 | Premium | H | SI2 | 61.0 | 58.0 | 2757 | 6.15 | 6.12 | 3.74 | no |
| 53939 | 0.75 | Ideal | D | SI2 | 62.2 | 55.0 | 2757 | 5.83 | 5.87 | 3.64 | yes |
Ejercicio 6: Eliminación de columnas de un DataFrame¶
Por último, vamos a ver cómo eliminar columnas de un DataFrame de pandas. Por ejemplo, borraremos las columnas rounded_price y rounded_price_to_100multiple
Cargue la biblioteca pandas
import pandas as pd
Leer los archivos de la URL en el DataFrame de pandas
diamonds_df = pd.read_csv(diamonds_url)
diamonds_df.head()
| carat | cut | color | clarity | depth | table | price | x | y | z | |
|---|---|---|---|---|---|---|---|---|---|---|
| 0 | 0.23 | Ideal | E | SI2 | 61.5 | 55.0 | 326 | 3.95 | 3.98 | 2.43 |
| 1 | 0.21 | Premium | E | SI1 | 59.8 | 61.0 | 326 | 3.89 | 3.84 | 2.31 |
| 2 | 0.23 | Good | E | VS1 | 56.9 | 65.0 | 327 | 4.05 | 4.07 | 2.31 |
| 3 | 0.29 | Premium | I | VS2 | 62.4 | 58.0 | 334 | 4.20 | 4.23 | 2.63 |
| 4 | 0.31 | Good | J | SI2 | 63.3 | 58.0 | 335 | 4.34 | 4.35 | 2.75 |
Añadir la columna price_per_carat al DataFrame
diamonds_df['price_per_carat'] = diamonds_df['price']/diamonds_df['carat']
diamonds_df.head()
| carat | cut | color | clarity | depth | table | price | x | y | z | price_per_carat | |
|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | 0.23 | Ideal | E | SI2 | 61.5 | 55.0 | 326 | 3.95 | 3.98 | 2.43 | 1417.391304 |
| 1 | 0.21 | Premium | E | SI1 | 59.8 | 61.0 | 326 | 3.89 | 3.84 | 2.31 | 1552.380952 |
| 2 | 0.23 | Good | E | VS1 | 56.9 | 65.0 | 327 | 4.05 | 4.07 | 2.31 | 1421.739130 |
| 3 | 0.29 | Premium | I | VS2 | 62.4 | 58.0 | 334 | 4.20 | 4.23 | 2.63 | 1151.724138 |
| 4 | 0.31 | Good | J | SI2 | 63.3 | 58.0 | 335 | 4.34 | 4.35 | 2.75 | 1080.645161 |
Utilice la función np.where del paquete numpy de Python:
import numpy as np
diamonds_df['price_per_carat_is_high'] = np.where(diamonds_df['price_per_carat'] > 3500, 1, 0)
diamonds_df.tail()
| carat | cut | color | clarity | depth | table | price | x | y | z | price_per_carat | price_per_carat_is_high | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 53935 | 0.72 | Ideal | D | SI1 | 60.8 | 57.0 | 2757 | 5.75 | 5.76 | 3.50 | 3829.166667 | 1 |
| 53936 | 0.72 | Good | D | SI1 | 63.1 | 55.0 | 2757 | 5.69 | 5.75 | 3.61 | 3829.166667 | 1 |
| 53937 | 0.70 | Very Good | D | SI1 | 62.8 | 60.0 | 2757 | 5.66 | 5.68 | 3.56 | 3938.571429 | 1 |
| 53938 | 0.86 | Premium | H | SI2 | 61.0 | 58.0 | 2757 | 6.15 | 6.12 | 3.74 | 3205.813953 | 0 |
| 53939 | 0.75 | Ideal | D | SI2 | 62.2 | 55.0 | 2757 | 5.83 | 5.87 | 3.64 | 3676.000000 | 1 |
Aplicar una función compleja para redondear el precio de los diamantes hasta su tope:
import math
diamonds_df['rounded_price'] = diamonds_df['price'].apply(math.ceil)
diamonds_df.head()
| carat | cut | color | clarity | depth | table | price | x | y | z | price_per_carat | price_per_carat_is_high | rounded_price | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | 0.23 | Ideal | E | SI2 | 61.5 | 55.0 | 326 | 3.95 | 3.98 | 2.43 | 1417.391304 | 0 | 326 |
| 1 | 0.21 | Premium | E | SI1 | 59.8 | 61.0 | 326 | 3.89 | 3.84 | 2.31 | 1552.380952 | 0 | 326 |
| 2 | 0.23 | Good | E | VS1 | 56.9 | 65.0 | 327 | 4.05 | 4.07 | 2.31 | 1421.739130 | 0 | 327 |
| 3 | 0.29 | Premium | I | VS2 | 62.4 | 58.0 | 334 | 4.20 | 4.23 | 2.63 | 1151.724138 | 0 | 334 |
| 4 | 0.31 | Good | J | SI2 | 63.3 | 58.0 | 335 | 4.34 | 4.35 | 2.75 | 1080.645161 | 0 | 335 |
Escribe un código para crear una función definida por el usuario:
import math
def get_100_multiple_ceil(x):
y = math.ceil(x/100)*100
return y
diamonds_df['rounded_price_to_100multiple']=diamonds_df['price'].apply(get_100_multiple_ceil)
diamonds_df.head()
| carat | cut | color | clarity | depth | table | price | x | y | z | price_per_carat | price_per_carat_is_high | rounded_price | rounded_price_to_100multiple | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | 0.23 | Ideal | E | SI2 | 61.5 | 55.0 | 326 | 3.95 | 3.98 | 2.43 | 1417.391304 | 0 | 326 | 400 |
| 1 | 0.21 | Premium | E | SI1 | 59.8 | 61.0 | 326 | 3.89 | 3.84 | 2.31 | 1552.380952 | 0 | 326 | 400 |
| 2 | 0.23 | Good | E | VS1 | 56.9 | 65.0 | 327 | 4.05 | 4.07 | 2.31 | 1421.739130 | 0 | 327 | 400 |
| 3 | 0.29 | Premium | I | VS2 | 62.4 | 58.0 | 334 | 4.20 | 4.23 | 2.63 | 1151.724138 | 0 | 334 | 400 |
| 4 | 0.31 | Good | J | SI2 | 63.3 | 58.0 | 335 | 4.34 | 4.35 | 2.75 | 1080.645161 | 0 | 335 | 400 |
Eliminar las columnas rounded_price y rounded_price_to_100multiple utilizando la función drop:
diamonds_df = diamonds_df.drop(columns = ['rounded_price', 'rounded_price_to_100multiple'])
diamonds_df.head()
| carat | cut | color | clarity | depth | table | price | x | y | z | price_per_carat | price_per_carat_is_high | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | 0.23 | Ideal | E | SI2 | 61.5 | 55.0 | 326 | 3.95 | 3.98 | 2.43 | 1417.391304 | 0 |
| 1 | 0.21 | Premium | E | SI1 | 59.8 | 61.0 | 326 | 3.89 | 3.84 | 2.31 | 1552.380952 | 0 |
| 2 | 0.23 | Good | E | VS1 | 56.9 | 65.0 | 327 | 4.05 | 4.07 | 2.31 | 1421.739130 | 0 |
| 3 | 0.29 | Premium | I | VS2 | 62.4 | 58.0 | 334 | 4.20 | 4.23 | 2.63 | 1151.724138 | 0 |
| 4 | 0.31 | Good | J | SI2 | 63.3 | 58.0 | 335 | 4.34 | 4.35 | 2.75 | 1080.645161 | 0 |
Ejercicio 7: Escribir un DataFrame en un archivo¶
En este ejercicio, escribiremos un DataFrame de diamantes en un archivo .csv. Para ello, utilizaremos el siguiente código:
Cargue la biblioteca pandas
import pandas as pd
Leer los archivos de la URL en el DataFrame de pandas
diamonds_df = pd.read_csv(diamonds_url)
diamonds_df.head()
| carat | cut | color | clarity | depth | table | price | x | y | z | |
|---|---|---|---|---|---|---|---|---|---|---|
| 0 | 0.23 | Ideal | E | SI2 | 61.5 | 55.0 | 326 | 3.95 | 3.98 | 2.43 |
| 1 | 0.21 | Premium | E | SI1 | 59.8 | 61.0 | 326 | 3.89 | 3.84 | 2.31 |
| 2 | 0.23 | Good | E | VS1 | 56.9 | 65.0 | 327 | 4.05 | 4.07 | 2.31 |
| 3 | 0.29 | Premium | I | VS2 | 62.4 | 58.0 | 334 | 4.20 | 4.23 | 2.63 |
| 4 | 0.31 | Good | J | SI2 | 63.3 | 58.0 | 335 | 4.34 | 4.35 | 2.75 |
Escriba el conjunto de datos de los diamantes en un archivo .csv:
diamonds_df.to_csv('diamonds_modified.csv')
Por defecto, la función to_csv genera un archivo que incluye las cabeceras de las columnas y los números de las filas. así como los números de fila. Añade un parámetro
index=Falsepara excluir los números de fila:
diamonds_df.to_csv('diamonds_modified.csv', index = False)
Ahora que tenemos una idea básica de cómo cargar y manejar los datos en un objeto DataFrame de pandas, vamos a empezar a hacer algunos gráficos simples a partir de los datos.
matplotlib es una biblioteca de trazado disponible en la mayoría de las distribuciones de Python y es la es la base de varios paquetes de ploteo, incluyendo la funcionalidad de ploteo incorporada en pandas y seaborn. matplotlib permite controlar todos los aspectos de una figura y es conocido por ser muy detallado.
Exercise 8: Trazado y análisis de un histograma¶
En este ejercicio, crearemos un histograma de la frecuencia de los diamantes en el conjunto de datos con sus respectivas especificaciones de carat (quilates) en el eje \(x\):
Cargue la biblioteca pandas
import pandas as pd
import seaborn as sns
Leer los archivos de la URL en el DataFrame de pandas
diamonds_df = pd.read_csv(diamonds_url)
diamonds_df.head()
| carat | cut | color | clarity | depth | table | price | x | y | z | |
|---|---|---|---|---|---|---|---|---|---|---|
| 0 | 0.23 | Ideal | E | SI2 | 61.5 | 55.0 | 326 | 3.95 | 3.98 | 2.43 |
| 1 | 0.21 | Premium | E | SI1 | 59.8 | 61.0 | 326 | 3.89 | 3.84 | 2.31 |
| 2 | 0.23 | Good | E | VS1 | 56.9 | 65.0 | 327 | 4.05 | 4.07 | 2.31 |
| 3 | 0.29 | Premium | I | VS2 | 62.4 | 58.0 | 334 | 4.20 | 4.23 | 2.63 |
| 4 | 0.31 | Good | J | SI2 | 63.3 | 58.0 | 335 | 4.34 | 4.35 | 2.75 |
Trazar un histograma utilizando el conjunto de datos de diamantes donde el eje x axis = carat. El eje \(y\) de este gráfico indica el número de diamantes del conjunto de datos con la especificación de carat en el eje \(x\).
diamonds_df.hist(column='carat')
array([[<AxesSubplot:title={'center':'carat'}>]], dtype=object)
La función hist tiene un parámetro llamado bins, que se refiere literalmente al número de intervalos de igual tamaño en los que se dividen los puntos de datos. Por defecto el parámetro bins está fijado en 10 en pandas. Podemos cambiarlo por un número diferente diferente, si lo deseamos.
diamonds_df.hist(column = 'carat', bins = 50)
array([[<AxesSubplot:title={'center':'carat'}>]], dtype=object)
Ahora, veamos la misma función utilizando
seaborn. Note quepandasestablece el parámetro bins a un valor por defecto de 10, pero seaborn infiere un bin de tamaño apropiado basado en la distribución estadística del conjunto de datos.
import seaborn as sns
sns.distplot(diamonds_df.carat)
<AxesSubplot:xlabel='carat', ylabel='Density'>
Por defecto, la función distplot también incluye una curva suavizada sobre el histograma, llamada estimación de la densidad del kernel (KDE). Si queremos eliminar el KDE y mirar sólo el histograma, podemos utilizar el parámetro kde=False.
sns.distplot(diamonds_df.carat, kde = False)
<AxesSubplot:xlabel='carat'>
Una transformación logarítmica ayuda a identificar más tendencias. Por ejemplo, en el siguiente gráfico, el eje \(x\) muestra los valores transformados en logaritmos de la variable del precio, y vemos que hay dos picos que indican dos tipos de diamantes: uno con un precio alto y otro con un precio bajo
import numpy as np
sns.distplot(np.log(diamonds_df.price))
<AxesSubplot:xlabel='price', ylabel='Density'>
Qué valores de las características son más frecuentes en el conjunto de datos (en este caso, hay un pico en torno a 6.8 y otro pico entre 8.5 y 9, nótese que log(price) = valores, en este caso
Exercise 9: Creación de un gráfico de barras y cálculo de la distribución del precio medio¶
En este ejercicio, aprenderemos a crear una tabla utilizando la función
pandas crosstab. Utilizaremos una tabla para generar un gráfico de barras. A continuación, exploraremos un gráfico de barras generado con la bibliotecaseaborny calcularemos la distribución del precio medio. Para ello, vamos a realizar los siguientes pasos
Cargue la biblioteca pandas
import pandas as pd
import seaborn as sns
Leer los archivos de la URL en el DataFrame de pandas
diamonds_df = pd.read_csv(diamonds_url)
diamonds_df.head()
| carat | cut | color | clarity | depth | table | price | x | y | z | |
|---|---|---|---|---|---|---|---|---|---|---|
| 0 | 0.23 | Ideal | E | SI2 | 61.5 | 55.0 | 326 | 3.95 | 3.98 | 2.43 |
| 1 | 0.21 | Premium | E | SI1 | 59.8 | 61.0 | 326 | 3.89 | 3.84 | 2.31 |
| 2 | 0.23 | Good | E | VS1 | 56.9 | 65.0 | 327 | 4.05 | 4.07 | 2.31 |
| 3 | 0.29 | Premium | I | VS2 | 62.4 | 58.0 | 334 | 4.20 | 4.23 | 2.63 |
| 4 | 0.31 | Good | J | SI2 | 63.3 | 58.0 | 335 | 4.34 | 4.35 | 2.75 |
Imprime los valores únicos de la columna corte:
diamonds_df.cut.unique()
array(['Ideal', 'Premium', 'Good', 'Very Good', 'Fair'], dtype=object)
Imprime los valores únicos de la columna claridad:
diamonds_df.clarity.unique()
array(['SI2', 'SI1', 'VS1', 'VS2', 'VVS2', 'VVS1', 'I1', 'IF'],
dtype=object)
unique()devuelve un array. Hay cinco cualidades únicas de cut y ocho valores únicos en clarity. El número de valores únicos se puede obtener utilizandonunique()en `pandas.
Para obtener los recuentos de diamantes de cada calidad de cut, primero creamos una tabla utilizando la función pandas crosstab():
cut_count_table = pd.crosstab(index = diamonds_df['cut'], columns = 'count')
cut_count_table
| col_0 | count |
|---|---|
| cut | |
| Fair | 1610 |
| Good | 4906 |
| Ideal | 21551 |
| Premium | 13791 |
| Very Good | 12082 |
Pase estos recuentos a otra función pandas, plot(kind=’bar’):
cut_count_table.plot(kind = 'bar')
<AxesSubplot:xlabel='cut'>
Vemos que la mayoría de los diamantes del conjunto de datos son de la calidad de corte Ideal, seguidos de Premium, Very Good, Good y Fair. Ahora, veamos cómo generar el mismo gráfico utilizando seaborn.
Generate the same bar plot using
seaborn
sns.catplot("cut", data = diamonds_df, aspect = 1.5, kind = "count", color = "b")
<seaborn.axisgrid.FacetGrid at 0x7f57aeef2e10>
Observe cómo la función catplot() no requiere que creemos la tabla de recuento intermedia (utilizando pd.crosstab()), y reduce un paso en el proceso de trazado.
A continuación, se muestra cómo se obtiene la distribución del precio medio de las diferentes calidades de cut utilizando seaborn
import seaborn as sns
from numpy import median, mean
sns.set(style = "whitegrid")
ax = sns.barplot(x = "cut", y = "price", data = diamonds_df, estimator = mean)
Aquí, las líneas negras (barras de error) de los rectángulos indican la incertidumbre (o dispersión de los valores) en torno a la estimación de la media. Las funciones mencionadas van mucho más allá de un simple recuento: aplican una función que calcula una medida de tendencia central (por defecto es el valor medio) y muestran, aplicando bootstrapping, el intervalo de confianza del 95% para dicha medida. Por defecto, este valor está fijado en un 95% de confianza. ¿Cómo lo cambiamos? Utilizando el parámetro ci=68, por ejemplo, lo fijamos en el 68%. También podemos representar la desviación estándar en los precios utilizando ci=sd.
Reordenar las barras del eje x utilizando el orden:
ax = sns.barplot(x = "cut", y = "price", data = diamonds_df, estimator = mean, ci = 68,
order=['Ideal','Good','Very Good','Fair','Premium'])
Exercise 10: Creación de gráficos de barras agrupados por una característica específica¶
En este ejercicio, utilizaremos el conjunto de datos de los diamantes para generar la distribución de los precios con respecto al color para cada calidad de corte. En el ejercicio 7, vimos la distribución de precios para diamantes de diferentes calidades de talla. Ahora, nos gustaría ver la variación de cada color:
Cargue la biblioteca pandas
import pandas as pd
import seaborn as sns
Leer los archivos de la URL en el DataFrame de pandas
diamonds_df = pd.read_csv(diamonds_url)
diamonds_df.tail()
| carat | cut | color | clarity | depth | table | price | x | y | z | |
|---|---|---|---|---|---|---|---|---|---|---|
| 53935 | 0.72 | Ideal | D | SI1 | 60.8 | 57.0 | 2757 | 5.75 | 5.76 | 3.50 |
| 53936 | 0.72 | Good | D | SI1 | 63.1 | 55.0 | 2757 | 5.69 | 5.75 | 3.61 |
| 53937 | 0.70 | Very Good | D | SI1 | 62.8 | 60.0 | 2757 | 5.66 | 5.68 | 3.56 |
| 53938 | 0.86 | Premium | H | SI2 | 61.0 | 58.0 | 2757 | 6.15 | 6.12 | 3.74 |
| 53939 | 0.75 | Ideal | D | SI2 | 62.2 | 55.0 | 2757 | 5.83 | 5.87 | 3.64 |
Utilice el parámetro
huepara trazar grupos anidados:
ax = sns.barplot(x = "cut", y = "price", hue = 'color', data = diamonds_df)
Aquí podemos observar que los patrones de precios de los diamantes de diferentes colores son similares para cada calidad de talla.
Exercise 11: Cómo ajustar los parámetros de un gráfico de barras agrupadas¶
En este ejercicio, modificaremos los parámetros de los gráficos, por ejemplo,
hue, de un gráfico de barras agrupadas. Veremos cómo colocar las leyendas y las etiquetas de los ejes en los lugares adecuados y también exploraremos la función de rotación
Cargue la biblioteca pandas
import pandas as pd
import seaborn as sns
Leer los archivos de la URL en el DataFrame de pandas
diamonds_df = pd.read_csv(diamonds_url)
diamonds_df.head()
| carat | cut | color | clarity | depth | table | price | x | y | z | |
|---|---|---|---|---|---|---|---|---|---|---|
| 0 | 0.23 | Ideal | E | SI2 | 61.5 | 55.0 | 326 | 3.95 | 3.98 | 2.43 |
| 1 | 0.21 | Premium | E | SI1 | 59.8 | 61.0 | 326 | 3.89 | 3.84 | 2.31 |
| 2 | 0.23 | Good | E | VS1 | 56.9 | 65.0 | 327 | 4.05 | 4.07 | 2.31 |
| 3 | 0.29 | Premium | I | VS2 | 62.4 | 58.0 | 334 | 4.20 | 4.23 | 2.63 |
| 4 | 0.31 | Good | J | SI2 | 63.3 | 58.0 | 335 | 4.34 | 4.35 | 2.75 |
ax = sns.barplot(x = "cut", y = "price", hue = 'color', data = diamonds_df)
ax = sns.barplot(x='cut', y='price', hue='color', data=diamonds_df)
ax.legend(loc='upper right', ncol=4)
<matplotlib.legend.Legend at 0x7f57ae661d68>
En la llamada anterior a ax.legend(), el parámetro ncol denota el número de columnas en las que deben organizarse los valores de la leyenda, y el parámetro loc especifica la ubicación de la leyenda y puede tomar cualquiera de los ocho valores 'upper left', 'upper right', 'lower left', 'lower right'.
Para modificar las etiquetas de los ejes \(𝑥\) y \(𝑦\), introduzca el siguiente código
ax = sns.barplot(x='cut', y='price', hue='color', data=diamonds_df)
ax.legend(loc='upper right', ncol=4)
ax.set_xlabel('Cut', fontdict={'fontsize' : 12})
ax.set_ylabel('Price', fontdict={'fontsize' : 12})
Text(0, 0.5, 'Price')
Del mismo modo, utilice esto para modificar el tamaño de la fuente y la rotación del eje \(x\) de la garrapata etiquetas:
ax = sns.barplot(x='cut', y='price', hue='color', data=diamonds_df)
ax.legend(loc='upper right',ncol=4)
ax.set_xticklabels(ax.get_xticklabels(), fontsize=13, rotation=45)
ax.set_xlabel('Cut', fontdict={'fontsize' : 12})
ax.set_ylabel('Price', fontdict={'fontsize' : 12})
Text(0, 0.5, 'Price')
La función de rotación es especialmente útil cuando las etiquetas de ticks son largas y se amontonan en el eje \(x\).
Exercise 12: Anotar un gráfico de barras¶
En este ejercicio, anotaremos un gráfico de barras, generado con la función catplot de seaborn, utilizando una nota justo encima del gráfico.
Cargue la biblioteca pandas
import pandas as pd
import seaborn as sns
import matplotlib.pyplot as plt
Leer los archivos de la URL en el DataFrame de pandas
diamonds_df = pd.read_csv(diamonds_url)
diamonds_df.head()
| carat | cut | color | clarity | depth | table | price | x | y | z | |
|---|---|---|---|---|---|---|---|---|---|---|
| 0 | 0.23 | Ideal | E | SI2 | 61.5 | 55.0 | 326 | 3.95 | 3.98 | 2.43 |
| 1 | 0.21 | Premium | E | SI1 | 59.8 | 61.0 | 326 | 3.89 | 3.84 | 2.31 |
| 2 | 0.23 | Good | E | VS1 | 56.9 | 65.0 | 327 | 4.05 | 4.07 | 2.31 |
| 3 | 0.29 | Premium | I | VS2 | 62.4 | 58.0 | 334 | 4.20 | 4.23 | 2.63 |
| 4 | 0.31 | Good | J | SI2 | 63.3 | 58.0 | 335 | 4.34 | 4.35 | 2.75 |
Generar un gráfico de barras utilizando la función
catplotde la bibliotecaseaborn
ax = sns.catplot("cut", data=diamonds_df, aspect=1.5, kind="count", color="b")
Anote la columna que pertenece a la categoría Ideal:
ideal_group = diamonds_df.loc[diamonds_df['cut']=='Ideal']
ideal_group.head()
| carat | cut | color | clarity | depth | table | price | x | y | z | |
|---|---|---|---|---|---|---|---|---|---|---|
| 0 | 0.23 | Ideal | E | SI2 | 61.5 | 55.0 | 326 | 3.95 | 3.98 | 2.43 |
| 11 | 0.23 | Ideal | J | VS1 | 62.8 | 56.0 | 340 | 3.93 | 3.90 | 2.46 |
| 13 | 0.31 | Ideal | J | SI2 | 62.2 | 54.0 | 344 | 4.35 | 4.37 | 2.71 |
| 16 | 0.30 | Ideal | I | SI2 | 62.0 | 54.0 | 348 | 4.31 | 4.34 | 2.68 |
| 39 | 0.33 | Ideal | I | SI2 | 61.8 | 55.0 | 403 | 4.49 | 4.51 | 2.78 |
Encuentre la ubicación de la coordenada \(x\) donde debe colocarse la anotación:
x = ideal_group.index.tolist()[0]
Encuentre la ubicación de la coordenada \(y\) donde debe colocarse la anotación:
y = len(ideal_group)
Imprime la ubicación de las coordenadas \(x\) e \(y\):
print(x)
print(y)
0
21551
Anota la gráfica con una nota:
sns.catplot("cut", data=diamonds_df, aspect=1.5, kind="count", color="b")
plt.annotate('excellent polish and symmetry ratings;\nreflects almost all the light that enters it',
xy=(x,y), xytext=(x+0.3, y+2000), arrowprops=dict(facecolor='red'))
Text(0.3, 23551, 'excellent polish and symmetry ratings;\nreflects almost all the light that enters it')
Ahora, parece que hay muchos parámetros en la función de anotación. La documentación oficial de Matplotlib cubre todos los detalles
Tarea 1.1¶
Trabajaremos con el conjunto de datos de 120 años de historia olímpica adquirido por Randi Griffin en Randi-Griffin y puesto a disposición en athlete_events. - Su tarea consiste en identificar los cinco deportes más importantes según el mayor número de medallas otorgadas en el año 2016, y luego realizar el siguiente análisis:
Genere un gráfico que indique el número de medallas concedidas en cada uno de los cinco principales deportes en 2016.
Trace un gráfico que represente la distribución de la edad de los ganadores de medallas en los cinco principales deportes en 2016.
Descubre qué equipos nacionales ganaron el mayor número de medallas en los cinco principales deportes en 2016.
Observe la tendencia del peso medio de los atletas masculinos y femeninos ganadores en los cinco principales deportes en 2016
Pasos principales
Descargue el conjunto de datos y formatéelo como un DataFrame de pandas.
Filtra el DataFrame para incluir solo las filas correspondientes a los ganadores de medallas de 2016.
Descubre las medallas concedidas en 2016 en cada deporte.
Enumera los cinco deportes más importantes en función del mayor número de medallas concedidas. Filtra el DataFrame una vez más para incluir solo los registros de los cinco deportes principales en 2016.
Genere un gráfico de barras con los recuentos de registros correspondientes a cada uno de los cinco deportes principales.
Generar un histograma para la característica Edad de todos los ganadores de medallas en los cinco deportes principales (2016).
Genera un gráfico de barras que indique cuántas medallas ganó el equipo de cada país en los cinco deportes principales en 2016.
Genere un gráfico de barras que indique el peso medio de los jugadores, clasificados en función del género, que ganaron en los cinco principales deportes en 2016.
Visualización estática¶
Este capítulo es un manual sobre los diferentes tipos de visualización estática y los contextos en los que son más eficaces. Utilizando seaborn, aprenderá a crear una variedad de variedad de gráficos y a seleccionar el tipo correcto de visualización para la representación más adecuada de sus datos.
En esta sección, estudiaremos el contexto de los gráficos que presentan patrones globales en los datos, como por ejemplo:
Gráficos que muestran la varianza de las características individuales de los datos, como los histogramas
Gráficos que muestran cómo varían las diferentes características presentes en los datos entre sí, como los gráficos de dispersión, los gráficos de líneas y los mapas de calor.
Scatter plot
Un gráfico de dispersión es un gráfico simple que presenta los valores de dos características en un conjunto de datos.
Cada punto de datos se representa mediante un punto con la coordenada \(x\) como valor de la primera característica y la coordenada \(y\) como valor de la segunda característica.
Un gráfico de dispersión es una gran herramienta para aprender más sobre dos atributos numéricos.
Los gráficos de dispersión pueden ayudar a descubrir las relaciones entre diferentes características de los datos, como el tiempo y las ventas, la ingesta de alimentos y las estadísticas de salud en varios contextos.
Ejercicio 13: Creación de un gráfico de dispersión estático¶
En este ejercicio, generaremos un gráfico de dispersión para examinar la relación entre el peso (weight) y el millaje (mpg) de los vehículos del conjunto de datos mpg. Para ello, vamos a seguir los siguientes pasos:
Abra un cuaderno Jupyter e importe los módulos de Python necesarios:
import seaborn as sns
Importe el conjunto de datos de seaborn:
mpg_df = sns.load_dataset("mpg")
Generar un gráfico de dispersión utilizando la función scatterplot():
ax = sns.scatterplot(x="weight", y="mpg", data=mpg_df)
Observación: Nótese que el gráfico de dispersión muestra una disminución del mileage (mpg) con un aumento del weight. Es una visión útil de las relaciones entre las diferentes características del conjunto de datos.
Ejercicio 14: Creación de un gráfico hexagonal estático Binning¶
También existe una versión más elegante de los gráficos de dispersión, llamada hexagonal binning plot (hexbin plot). En este ejercicio, generaremos un diagrama de dispersión hexagonal para comprender mejor la relación entre el peso (weight) y el millaje (mileage (mpg)):
Abra un cuaderno Jupyter e importe los módulos de Python necesarios:
import seaborn as sns
Importe el conjunto de datos de seaborn:
mpg_df = sns.load_dataset("mpg")
Trazar un gráfico hexbin usando jointplot con el tipo establecido en hex:
sns.set(style="ticks")
sns.jointplot(mpg_df.weight, mpg_df.mpg, kind="hex", color="#4CB391")
<seaborn.axisgrid.JointGrid at 0x7f57ae726390>
Observación: Como puede observar, el histograma de los ejes superior y derecho representa la varianza de las características representadas por los ejes \(x\) e \(y\) respectivamente (mpg y weight, en este ejemplo). Además, es posible que haya notado en el gráfico de dispersión anterior que los datos se superponían fuertemente en ciertas áreas, ocultando la distribución real de las características. Los gráficos Hexbin son una buena herramienta de visualización utilizada cuando los datos son muy densos.
Ejercicio 15: Creación de un gráfico de contorno estático¶
Otra alternativa a los gráficos de dispersión cuando los puntos de datos están densamente poblados en regiones específicas es un gráfico de contorno. En este ejercicio, crearemos un gráfico de contorno para mostrar la relación entre weight y el mileage en el conjunto de datos mpg. Podremos ver que la relación entre weight y mileage es más fuerte cuando hay mayor volumen de datos
Abra un cuaderno Jupyter e importe los módulos de Python necesarios:
import seaborn as sns
Importe el conjunto de datos de seaborn:
mpg_df = sns.load_dataset("mpg")
Crea un gráfico de contorno utilizando el método set_style
sns.set_style("white")
Generar un gráfico de estimación de la densidad del núcleo (KDE). Los dos primeros parámetros son matrices de \(X\) e \(Y\) coordenadas de los puntos de datos, el parámetro shade se establece en True para que los contornos se rellenen con un gradiente de color basado en el número de puntos de datos
sns.kdeplot(mpg_df.weight, mpg_df.mpg, shade=True)
<AxesSubplot:xlabel='weight', ylabel='mpg'>
Observación: En nuestro ejemplo de weight frente a mileage (mpg), el diagrama hexagonal y el diagrama de contorno indican que hay una determinada curva a lo largo de la cual la relación negativa entre el peso y el kilometraje es más fuerte, como es evidente por el mayor número de puntos de datos. La relación negativa se vuelve relativamente más débil a medida que nos alejamos de la curva (menos volumen de datos).
Ejercicio 16: Creación de un gráfico de líneas estáticas¶
Los gráficos de líneas representan la información como una serie de puntos de datos conectados por segmentos de líneas rectas. Son útiles para indicar la relación entre una característica numérica discreta (en el eje \(x\)), como model_year, y una característica numérica continua (en el eje \(y\)), como mpg del conjunto de datos mpg. En este ejercicio, crearemos un gráfico de dispersión para un par de características diferentes, model_year y mpg.
Abra un cuaderno Jupyter e importe los módulos de Python necesarios:
import seaborn as sns
Importe el conjunto de datos de seaborn:
mpg_df = sns.load_dataset("mpg")
Slecciones el estilo para la figura con
set_style
sns.set_style("white")
Crear un gráfico de dispersión bidimensional
ax1 = sns.scatterplot(x="model_year", y="mpg", data=mpg_df)
Observación: En este ejemplo, vemos que la característica model_year sólo toma valores discretos entre 70 y 82. Ahora, cuando tenemos una característica numérica discreta como esta (modelo_año), dibujar un gráfico de líneas uniendo los puntos de datos es una buena idea. Podemos dibujar un simple gráfico de líneas que muestre la relación entre año_modelo y kilometraje con el siguiente código.
Dibuja un gráfico lineal simple para mostrar la relación entre model_year y mileage
ax = sns.lineplot(x="model_year", y="mpg", data=mpg_df)
Observación: Como podemos ver, los puntos conectados por la línea sólida representan la media de la característica del eje \(y\) en la coordenada \(x\) correspondiente. El área sombreada alrededor de la línea muestra el intervalo de confianza para la característica del eje \(y\) (por defecto, seaborn establece el intervalo de confianza del 95%). El parámetro ci puede utilizarse para cambiar a un intervalo de confianza diferente.
Cambiar el intervalo de confianza a 68
sns.lineplot(x="model_year", y="mpg", data=mpg_df, ci=68)
<AxesSubplot:xlabel='model_year', ylabel='mpg'>
Observación: Como podemos ver en el gráfico anterior, el intervalo de confianza del 68% se traduce en un rango de valores de características en el que están presentes el 68% de los puntos de datos. Los gráficos de líneas son excelentes técnicas de visualización para escenarios en los que tenemos datos que cambian con el tiempo, eje \(x\), podría representar la fecha o el tiempo, y el gráfico ayudaría a visualizar cómo un valor varía a lo largo de ese periodo
Ejercicio 17: Presentación de datos a través del tiempo con múltiples gráficos de líneas¶
En este ejemplo, veremos cómo presentar los datos a través del tiempo con múltiples gráficos de líneas. En este ejemplo utilizamos el conjunto de datos de vuelos
Abra un cuaderno Jupyter e importe los módulos de Python necesarios:
import seaborn as sns
Importe el conjunto de datos de seaborn:
flights_df = sns.load_dataset("flights")
print(flights_df.head())
year month passengers
0 1949 Jan 112
1 1949 Feb 118
2 1949 Mar 132
3 1949 Apr 129
4 1949 May 121
Supongamos que quiere observar cómo varía el número de pasajeros entre meses en diferentes años. ¿Cómo mostraría esta información? Una opción es dibujar varios gráficos de líneas en una sola figura.
Crear varias gráficas para los meses de diciembre y enero
fig,ax=plt.subplots()
ax = sns.lineplot(x="year", y="passengers", data=flights_df[flights_df['month']=='Jan'], color='green')
ax = sns.lineplot(x="year", y="passengers", data=flights_df[flights_df['month']=='Feb'], color='red')
ax = sns.lineplot(x="year", y="passengers", data=flights_df[flights_df['month']=='Mar'], color='blue')
ax = sns.lineplot(x="year", y="passengers", data=flights_df[flights_df['month']=='Apr'], color='cyan')
ax = sns.lineplot(x="year", y="passengers", data=flights_df[flights_df['month']=='May'], color='pink')
ax = sns.lineplot(x="year", y="passengers", data=flights_df[flights_df['month']=='Jun'], color='black')
ax = sns.lineplot(x="year", y="passengers", data=flights_df[flights_df['month']=='Jul'], color='grey')
ax = sns.lineplot(x="year", y="passengers", data=flights_df[flights_df['month']=='Aug'], color='yellow')
ax = sns.lineplot(x="year", y="passengers", data=flights_df[flights_df['month']=='Sep'], color='turquoise')
ax = sns.lineplot(x="year", y="passengers", data=flights_df[flights_df['month']=='Oct'], color='orange')
ax = sns.lineplot(x="year", y="passengers", data=flights_df[flights_df['month']=='Nov'], color='darkgreen')
ax = sns.lineplot(x="year", y="passengers", data=flights_df[flights_df['month']=='Dec'], color='darkred')
Observación Con este ejemplo de 12 gráficos de líneas, podemos ver cómo una figura con demasiados gráficos de líneas rápidamente comienza a abarrotarse y a confundirse. Por lo tanto, para ciertos escenarios, los gráficos de líneas no son no son atractivos ni útiles. Entonces, ¿cuál es la alternativa para nuestro caso de uso? Lo veremos en el siguiente ejercicio
Ejercicio 18: Creación y exploración de un mapa de calor estático¶
Un heatmap es una representación visual de una característica numérica continua específica en función de otras dos características discretas (ya sea una categórica o una numérica discreta) en el conjunto de datos. En este ejercicio, exploraremos y crearemos un mapa de calor. Utilizaremos el conjunto de datos de vuelos de la biblioteca seaborn para generar un mapa de calor que represente el número de pasajeros por mes en los años 1949-1960
Abra un cuaderno Jupyter e importe los módulos de Python necesarios:
import seaborn as sns
Importe el conjunto de datos de seaborn:
flights_df = sns.load_dataset("flights")
print(flights_df.head())
year month passengers
0 1949 Jan 112
1 1949 Feb 118
2 1949 Mar 132
3 1949 Apr 129
4 1949 May 121
Ahora tenemos que hacer pivotar el conjunto de datos sobre las variables requeridas utilizando la función pivot() antes de generar el mapa de calor. La función pivot toma primero como argumentos la característica que se mostrará en filas, luego la que se muestra en columnas y, por último, la característica cuya variación nos interesa observar. Utiliza los valores únicos de los índices/columnas especificados para formar los ejes del DataFrame resultante
df_pivoted = flights_df.pivot("month", "year", "passengers")
ax = sns.heatmap(df_pivoted)
Observación: Aquí podemos observar que el número total de vuelos anuales aumentó de forma constante desde 1949 a 1960. Además, los meses de julio y agosto parecen tener el mayor número de vuelos (en comparación con el resto de los meses) en todos los años de observación.
Utilice la opción clustermap para agrupar filas y columnas:
ax = sns.clustermap(df_pivoted, col_cluster=False, row_cluster=True)
Observación: Nótese que el orden de los meses se ha reordenado en los gráficos, pero algunos meses (por ejemplo, julio y agosto) se han mantenido juntos debido a sus tendencias similares. Tanto en julio como en agosto, el número de vuelos aumentó de forma relativamente más drástica en los últimos años hasta 1960. ¿Cómo se calcula la similitud entre filas y columnas? La respuesta es que depende de la métrica de distancia
Establecer la métrica como euclidiana
ax = sns.clustermap(df_pivoted, col_cluster=False)
Cambiar la métrica a correlación
ax = sns.clustermap(df_pivoted, row_cluster=False, metric='correlation')
Observación: Al leer sobre la métrica de la distancia, aprendemos que define la distancia entre dos filas/columnas. Sin embargo, si nos fijamos bien, vemos que el mapa de calor también agrupa no sólo filas o columnas individuales, sino también grupos de filas y columnas. filas o columnas individuales. Aquí es donde entra en juego la vinculación.
Ejercicio 19: Creación de vínculos en mapas térmicos estáticos¶
Si definimos la distancia entre dos clusters como la distancia entre los dos puntos de los clusters más cercanos entre sí, la regla se denomina enlace único (single linkage).
Si la regla es definir la distancia entre dos clusters como la distancia entre los puntos más alejados entre sí, se denomina vinculación completa (complete linkage).
Si la regla es definir la distancia como la media de todos los posibles pares de filas en los dos clústeres, se denomina vinculación media (average linkage).
En este ejercicio, generaremos un mapa de calor y comprenderemos el concepto de enlace único, completo y promedio en los mapas de calor utilizando el conjunto de datos flights.
Abra un cuaderno Jupyter e importe los módulos de Python necesarios:
import seaborn as sns
Importe el conjunto de datos de seaborn:
flights_df = sns.load_dataset("flights")
print(flights_df.head())
year month passengers
0 1949 Jan 112
1 1949 Feb 118
2 1949 Mar 132
3 1949 Apr 129
4 1949 May 121
Ahora necesitamos pivotar el conjunto de datos en las variables requeridas utilizando la función pivot() antes de generar el mapa de calor:
df_pivoted = flights_df.pivot("month", "year", "passengers")
ax = sns.heatmap(df_pivoted)
Enlaza los mapas de calor utilizando el código que sigue
ax = sns.clustermap(df_pivoted, col_cluster=False, metric='correlation', method='average')
ax = sns.clustermap(df_pivoted, row_cluster=False, metric='correlation', method='complete')
ax = sns.clustermap(df_pivoted, row_cluster=False, metric='correlation', method='single')
Observación Los mapas de calor también son una buena forma de visualizar lo que ocurre en un espacio 2D. Por ejemplo, pueden utilizarse para mostrar dónde hay más acción en el campo en un partido de fútbol. Del mismo modo, en un sitio web, los mapas de calor se pueden utilizar para mostrar las áreas que son más más frecuentadas por los usuarios.
Creación de gráficos para representar estadísticas¶
Cuando los conjuntos de datos son enormes, a veces resulta útil observar las estadísticas de resumen de una serie de características diferentes y hacerse una idea preliminar del conjunto de datos. Por ejemplo, las estadísticas de resumen de cualquier característica numérica incluyen medidas de tendencia central, como la media, y medidas de dispersión, como la desviación estándar. Los histogramas muestran la distribución de una característica dada en los datos, podemos hacer un gráfico un poco más informativo mostrando algunas estadísticas de resumen en el mismo gráfico.
Ejemplo 1: Histograma revisado¶
Importar los módulos de Python necesarios; cargar el conjunto de datos; elegir el número de intervalos y si la estimación de la densidad del kernel debe mostrarse o no; usar el color rojo para mostrar media utilizando una línea recta en el eje \(x\) (paralela al eje \(y\)); definir la ubicación de la leyenda:
import matplotlib.pyplot as plt
import seaborn as sns
import numpy as np
mpg_df = sns.load_dataset("mpg")
ax = sns.distplot(mpg_df.weight, bins=50, kde=False)
plt.axvline(x=np.mean(mpg_df.weight), color='red', label='mean')
plt.axvline(x=np.median(mpg_df.weight), color='orange', label='median')
plt.legend(loc='upper right')
<matplotlib.legend.Legend at 0x7f57ae73a7b8>
Este histograma muestra la distribución de la característica de peso junto con la media y la mediana. Observe que la media no es igual a la mediana, lo que significa que la característica no está distribuida normalmente.
Ejercicio 20: Creación y exploración de un gráfico de caja¶
Los gráficos de caja son una forma excelente de examinar la relación entre las estadísticas de resumen de una característica numérica en relación con otras características categóricas. En este ejercicio crearemos un diagrama para establecer la relación entre model_year and mileage using the mpg dataset. We’ll analyze manufacturing efficiency and the mileage of vehicles over a period of years. To do so, let’s go through the following steps
Importe la libreria seaborn
import seaborn as sns
Cargue el dataset
mpg_df = sns.load_dataset("mpg")
mpg_df.head()
| mpg | cylinders | displacement | horsepower | weight | acceleration | model_year | origin | name | |
|---|---|---|---|---|---|---|---|---|---|
| 0 | 18.0 | 8 | 307.0 | 130.0 | 3504 | 12.0 | 70 | usa | chevrolet chevelle malibu |
| 1 | 15.0 | 8 | 350.0 | 165.0 | 3693 | 11.5 | 70 | usa | buick skylark 320 |
| 2 | 18.0 | 8 | 318.0 | 150.0 | 3436 | 11.0 | 70 | usa | plymouth satellite |
| 3 | 16.0 | 8 | 304.0 | 150.0 | 3433 | 12.0 | 70 | usa | amc rebel sst |
| 4 | 17.0 | 8 | 302.0 | 140.0 | 3449 | 10.5 | 70 | usa | ford torino |
Crear un diagrama de cajas
sns.boxplot(x='model_year', y='mpg', data=mpg_df)
<AxesSubplot:xlabel='model_year', ylabel='mpg'>
Como podemos ver, los límites de la caja indican el rango intercuartil, el límite superior marca el cuartil del 25% y el límite inferior el cuartil del 75%. La línea horizontal dentro de la caja indica la mediana. Cualquier punto aislado fuera de los bigotes (las barras en forma de \(T\) por encima y por debajo de la caja) marca los valores atípicos, mientras que los propios bigotes muestran los valores mínimos y máximos que no son valores atípicos. Aparentemente, el millaje mejoró sustancialmente en los 80 en comparación con los 70.
Añadamos otra característica a nuestro mpg DataFrame que denote si el coche fue fabricado en los 70 o en los 80. Modifica el DataFrame mpg creando una nueva característica, model_decade
import numpy as np
mpg_df['model_decade'] = np.floor(mpg_df.model_year/10)*10
mpg_df['model_decade'] = mpg_df['model_decade'].astype(int)
mpg_df.tail()
| mpg | cylinders | displacement | horsepower | weight | acceleration | model_year | origin | name | model_decade | |
|---|---|---|---|---|---|---|---|---|---|---|
| 393 | 27.0 | 4 | 140.0 | 86.0 | 2790 | 15.6 | 82 | usa | ford mustang gl | 80 |
| 394 | 44.0 | 4 | 97.0 | 52.0 | 2130 | 24.6 | 82 | europe | vw pickup | 80 |
| 395 | 32.0 | 4 | 135.0 | 84.0 | 2295 | 11.6 | 82 | usa | dodge rampage | 80 |
| 396 | 28.0 | 4 | 120.0 | 79.0 | 2625 | 18.6 | 82 | usa | ford ranger | 80 |
| 397 | 31.0 | 4 | 119.0 | 82.0 | 2720 | 19.4 | 82 | usa | chevy s-10 | 80 |
Ahora, volvamos a dibujar nuestro gráfico de caja para ver la distribución de los millajes en las dos décadas
sns.boxplot(x='model_decade', y='mpg', data=mpg_df)
<AxesSubplot:xlabel='model_decade', ylabel='mpg'>
También podemos añadir otra característica, por ejemplo, la región de origen, y ver cómo afecta a la relación entre el kilometraje y el tiempo de fabricación, las dos características que hemos estado considerando hasta ahora
Use the hue parameter to group by origin
sns.boxplot(x='model_decade', y='mpg', data=mpg_df, hue='origin')
<AxesSubplot:xlabel='model_decade', ylabel='mpg'>
Como podemos ver, según el conjunto de datos de mpg, en los años 70 y principios de los 80, Europa y Japón produjeron coches con mejor millaje que los Estados Unidos.
Ejercicio 21: Creación de un gráfico de violín¶
¿Y si pudiéramos obtener una pista sobre la distribución completa de una característica numérica específica agrupada por otras características categóricas? La tipo de técnica de visualización adecuada en este caso es un gráfico de violín. Un gráfico de violín es similar a un grafico de caja pero incluye más detalles sobre las variaciones de los datos. En este ejercicio, utilizaremos el conjunto de datos mpg y generaremos un gráfico de violín que represente la variación detallada del millaje (mpg) en función de model_decade y la región de origen
Importe la libreria seaborn
import seaborn as sns
Cargue el dataset
mpg_df = sns.load_dataset("mpg")
Generar el gráfico de violín utilizando la función violinplot en seaborn
import numpy as np
mpg_df['model_decade'] = np.floor(mpg_df.model_year/10)*10
mpg_df['model_decade'] = mpg_df['model_decade'].astype(int)
sns.violinplot(x='model_decade', y='mpg', data=mpg_df, hue='origin')
<AxesSubplot:xlabel='model_decade', ylabel='mpg'>
Podemos ver aquí que, durante los años 70, mientras que la mayoría de los vehículos de EE.UU. tenían un millaje medio de 19 mpg, los vehículos de Japón y Europa tenían millajes medios de alrededor de 27 y 25 mpg. Mientras que el kilometraje de los vehículos en Europa y Japón aumentó entre 7 y 8 puntos en los años 80, el kilometraje medio de los vehículos en EE.UU. seguía siendo similar al de los vehículos en Japón y Europa en la década anterior.
Tarea 1.2¶
Estadísticas: Seguiremos trabajando con el conjunto de datos de 120 años de historia olímpica adquirido por Randi Griffin en Randi Griffin
Como especialista en visualización, su tarea consiste en crear dos parcelas para los ganadores de medallas de 2016 de cinco deportes: atletismo, natación, remo, fútbol y hockey
Crea un gráfico utilizando una técnica de visualización adecuada que presente de la mejor manera posible el patrón global de las características de height y weight de los ganadores de medallas de 2016 de los cinco deportes.
Crea un gráfico utilizando una técnica de visualización adecuada que presente de la mejor manera posible la estadística de resumen para la altura y el peso de los jugadores que ganaron cada tipo de medalla (oro/plata/bronce) en los datos.
Utilizar su creatividad y sus habilidades para sacar conclusiones importantes de los datos
Pasos importantes
Descargue el conjunto de datos y formatéelo como un pandas DataFrame
Filtrar el DataFrame para incluir únicamente las filas correspondientes a los ganadores de medallas de 2016 en los deportes mencionados en la descripción de la actividad
Observe las características del conjunto de datos y anote su tipo de datos: ¿son categóricos o numéricos?
Evaluar cuál sería la visualización adecuada para que un patrón global represente las características de height y weight
Evaluar cuál sería la visualización adecuada para representar las estadísticas resumidas de las características de height y weight en función de las medallas, separadas además por género de los atletas.
De la visualización estática a la interactiva¶
Objetivos `
Explicar las diferencias entre las visualizaciones estáticas e interactivas
Explicar la aplicación de las visualizaciones interactivas en diversos sectores
Crear gráficos interactivos con funcionalidades de
zoom, hoveryslideUtilizar las librerías
BokehyPlotly(Express) dePythonpara crear visualizaciones de datos interactivas
En este capítulo, pasaremos de las visualizaciones estáticas a las interactivas y estudiaremos las aplicaciones de las visualizaciones interactivas para diferentes escenarios.
Introducción¶
En la sección anterior hablamos de las visualizaciones de datos estáticas, es decir, gráficos y diagramas que están inmóviles y no pueden ser modificados o interactuados en tiempo real por el público.
Las visualizaciones de datos interactivas están un paso por delante de las estáticas. La definición de interactivo es algo que implica la comunicación entre dos o más cosas o personas que trabajan juntas. Por lo tanto, las visualizaciones interactivas son representaciones gráficas de datos analizados (estáticos o dinámicos) que pueden reaccionar y responder a las acciones del usuario en el momento.

Visualización estática versus interactiva¶
Aunque las visualizaciones estáticas de datos son un gran avance hacia el objetivo de extraer y explicar el valor y la información que contienen los conjuntos de datos, la adición de interactividad hace que estas visualizaciones vayan un paso más allá.
Las visualizaciones de datos interactivas tienen las siguientes cualidades:
Son más fáciles de explorar ya que permiten interactuar con los datos cambiando colores, parámetros y gráficos.
Se pueden manipular fácilmente y al instante. Ya que se puede interactuar con ellas, los gráficos se pueden cambiar delante del usuario. Por ejemplo, usando un deslizador interactivo. Cuando la posición de este deslizador cambia el gráfico también lo hace, además se úeden crear casillas de verificación que le permitan seleccionar los parámetros que desea ver.
Permiten acceder a los datos en tiempo real y a la información que proporcionan. Esto permite el análisis eficaz y rápido de las tendencias.
Son más fáciles de comprender, lo que permite a las organizaciones tomar mejores decisiones basadas en datos.
Eliminan la necesidad de tener varios gráficos para la misma información. Un solo gráfico interactivo es capaz de transmitir la misma información. Permiten observar relaciones (por ejemplo, causa y efecto).
Ejemplo¶
Empecemos con un ejemplo para entender lo que podemos conseguir mediante la visualización interactiva. Consideremos un dataset de socios inscritos en un gimnasio:
La siguiente es una visualización de datos estática en forma de gráfico de caja que describe el peso de las personas clasificadas por su sexo (0 es hombre, 1 es mujer y 2 es otro):

El único dato que podemos obtener de este gráfico es la relación entre el peso y el sexo. Sin embargo, hay una tercera característica presente en el conjunto de datos que se utiliza para generar este gráfico de caja: la edad. La adición de esta característica al gráfico estático anterior puede llevar a la confusión en cuanto a la comprensión de los datos.
Por lo tanto, estamos un poco atascados con respecto a mostrar la relación entre las tres características utilizando una visualización estática. Este problema de problema puede resolverse fácilmente creando una visualización interactiva, como se muestra aquí:

En el gráfico de caja anterior, se ha introducido un control deslizante para la característica de la edad. El usuario puede deslizar manualmente la posición del deslizador para observar la relación entre peso, el sexo y la edad en diferentes valores de edad. Además, hay una herramienta de desplazamiento que permite al usuario obtener más información sobre los datos.
El gráfico de caja anterior describe que, en este gimnasio, los únicos clientes de 46 años son los que se identifican como otros, y el más pesado de 46 años pesa 82 kilogramos, mientras que el más ligero pesa 56 kilogramos. El usuario puede deslizarse a otra posición para observar la relación entre peso y sexo a una edad diferente, como se muestra en el siguiente gráfico:

El gráfico anterior describe los datos a la edad de 34 años: no hay clientes masculinos del gimnasio; Sin embargo, la clienta más pesada de 34 años pesa 100 kilogramos, mientras que la más ligera pesa 71 kilogramos. más ligera pesa 71 kilogramos.
Pero aún hay más aspectos a tener en cuenta a la hora de diferenciar entre visualizaciones estáticas e interactivas. Veamos la siguiente tabla:
Visualización Estática |
Visualización Interactiva |
|
|---|---|---|
Medios/campos objetivo |
Medios impresos y presentaciones |
Aplicaciones web, social media, BI |
Coste de creación |
Bajo |
Alto |
Conexión a fuente de datos |
No requerida |
Requerida en caso dinamico |
Visualización |
Renderización facil |
Requiere diseño de UI |
Librerias de Python |
Matplotlib, Seaborn |
Bokeh, Plotly |
En última instancia, las visualizaciones de datos interactivas transforman el debate sobre los datos en el arte de contar historias, simplificando así el proceso de comprensión de lo que los datos intentan decirnos. Estos aspectos son los que separan las visualizaciones interactivas de las estáticas. Veamos algunas aplicaciones de las visualizaciones de datos interactivas.
Aplicaciones de las visualizaciones interactivas de datos¶
El aspecto clave de las visualizaciones de datos interactivas es su capacidad de responder y reaccionar a las entradas humanas en el momento o en un lapso de tiempo muy corto. En esta sección, veremos algunas entradas humanas, cómo pueden introducirse en las visualizaciones de datos, y el impacto que tienen en la comprensión de los datos
Slider: Un deslizador permite al usuario ver los datos correspondientes a un rango de algo. A medida que el usuario cambia la posición del deslizador, el gráfico cambia en tiempo real. Este permite al usuario ver varios gráficos en tiempo real:

Hover: Al pasar (hovering) el cursor por encima de un elemento de un gráfico, el usuario puede recibir más información sobre el punto de datos que la que se puede ver simplemente observando el gráfico. Esto es útil cuando la información que se desea transmitir no cabe en el propio gráfico (como valores precisos o descripciones breves). Veamos una herramienta de hover:

Zoom: Acercarse y alejarse de un gráfico es una característica que bastantes bibliotecas de visualización de datos interactivos crean por sí mismas. Le permiten centrarse en puntos de un gráfico y verlos más de cerca.
Clickable parameters: Hay varios tipos de parámetros clicables, como casillas de verificación y menús desplegables, que permiten al usuario elegir qué aspectos de los datos desea analizar y ver.

Hay bibliotecas de Python que se utilizan para crear estas funciones interactivas, que permiten que las visualizaciones tomen la entrada humana. En los capítulos anteriores, vimos dos bibliotecas de Python incorporadas:
matplotlibseaborn
Ambos son populares en la comunidad de visualización de datos. Con estas, podemos construir una visualización estática (un gráfico de dispersión estático que muestra la relación entre dos variables) como ésta:
Mientras que tanto matplotlib como seaborn son excelentes para las visualizaciones de datos estáticos, hay otras bibliotecas disponibles que hacen un buen trabajo de diseño de características interactivas. Dos de las bibliotecas Python de visualización de datos interactivos más populares son
bokehplotly
Esto nos ayuda a crear visualizaciones como las siguientes. Utilizaremos tanto
bokehcomoplotlyen los ejercicios de este capítulo para crear visualizaciones de datos interactivas.

Visualización interactiva de datos con Bokeh¶
bokehes una biblioteca de Python para la visualización interactiva de datos. Los gráficos deBokehse se crean apilando capas una encima de otra. El primer paso es crear una figura vacía figura, a la que se añaden elementos en capas. Estos elementos se conocen comoglifos, que pueden ser cualquier cosa, desde líneas hasta barras o círculos. A cadaglifose le adjuntan propiedades como el color, el tamaño y las coordenadas.
bokehes muy popular porque las visualizaciones se renderizan utilizandoHTMLyJavaScript, por lo que se suele elegir cuando se diseñan visualizaciones interactivas basadas en la web. Además, el módulobokeh.iocrea un archivo.htmlque contiene estático básico, junto con las características interactivas, y no requiere necesariamente un servidor para ejecutarse, lo que hace que la visualización sea muy fácil de desplegar.
En este capítulo, los siguientes ejercicios tienen como objetivo crear una visualización de datos interactiva para representar la relación entre las emisiones de dióxido de carbono y el PIB de un país utilizando la biblioteca
bokehde Python.
Ejercicio 22: Preparación de nuestro conjunto de datos¶
En este ejercicio, descargaremos y prepararemos nuestro conjunto de datos utilizando las bibliotecas incorporadas
pandasynumpy. Al final de este ejercicio, tendremos unDataFramesobre el que construiremos nuestras visualizaciones interactivas de datos. Utilizaremos los archivosco2.csvygapminder.csv. El primero consiste en las emisiones de dióxido de carbono por persona por año y por país, mientras que el segundo consiste en el PIB por año y por país.
Los siguientes pasos le ayudarán a preparar los datos:
Importar las bibliotecas
pandasynumpy:
import pandas as pd
import numpy as np
Guarde el archivo co2.csv en un DataFrame llamado co2, y el archivo gapminder.csv en un DataFrame llamado gm:
url_co2 = 'https://raw.githubusercontent.com/lihkir/Uninorte/main/AppliedStatisticMS/DataVisualizationRPython/Lectures/Python/PythonDataSets/co2.csv'
co2 = pd.read_csv(url_co2)
co2.head()
| country | 1800 | 1801 | 1802 | 1803 | 1804 | 1805 | 1806 | 1807 | 1808 | ... | 2005 | 2006 | 2007 | 2008 | 2009 | 2010 | 2011 | 2012 | 2013 | 2014 | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | Afghanistan | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | ... | 0.0529 | 0.0637 | 0.0854 | 0.154 | 0.242 | 0.294 | 0.412 | 0.35 | 0.316 | 0.299 |
| 1 | Albania | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | ... | 1.3800 | 1.2800 | 1.3000 | 1.460 | 1.480 | 1.560 | 1.790 | 1.68 | 1.730 | 1.960 |
| 2 | Algeria | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | ... | 3.2200 | 2.9900 | 3.1900 | 3.160 | 3.420 | 3.300 | 3.290 | 3.46 | 3.510 | 3.720 |
| 3 | Andorra | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | ... | 7.3000 | 6.7500 | 6.5200 | 6.430 | 6.120 | 6.120 | 5.870 | 5.92 | 5.900 | 5.830 |
| 4 | Angola | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | ... | 0.9800 | 1.1000 | 1.2000 | 1.180 | 1.230 | 1.240 | 1.250 | 1.33 | 1.250 | 1.290 |
5 rows × 216 columns
url_gm = 'https://raw.githubusercontent.com/lihkir/Uninorte/main/AppliedStatisticMS/DataVisualizationRPython/Lectures/Python/PythonDataSets/gapminder.csv'
gm = pd.read_csv(url_gm)
gm.head()
| Country | Year | fertility | life | population | child_mortality | gdp | region | |
|---|---|---|---|---|---|---|---|---|
| 0 | Afghanistan | 1964 | 7.671 | 33.639 | 10474903.0 | 339.7 | 1182.0 | South Asia |
| 1 | Afghanistan | 1965 | 7.671 | 34.152 | 10697983.0 | 334.1 | 1182.0 | South Asia |
| 2 | Afghanistan | 1966 | 7.671 | 34.662 | 10927724.0 | 328.7 | 1168.0 | South Asia |
| 3 | Afghanistan | 1967 | 7.671 | 35.170 | 11163656.0 | 323.3 | 1173.0 | South Asia |
| 4 | Afghanistan | 1968 | 7.671 | 35.674 | 11411022.0 | 318.1 | 1187.0 | South Asia |
Actualmente tenemos dos DataFrames separados, cada uno de ellos compuesto por datos que necesitamos para crear nuestra visualización de datos interactiva. Para crear la visualización, necesitamos combinar estos dos DataFrames y eliminar las columnas no deseadas.
Utilice
.drop_duplicates()para eliminar las instancias duplicadas del gm y guárdelo en un nuevo DataFrame llamado df_gm:
df_gm = gm[['Country', 'region']].drop_duplicates()
df_gm.head()
| Country | region | |
|---|---|---|
| 0 | Afghanistan | South Asia |
| 50 | Albania | Europe & Central Asia |
| 100 | Algeria | Middle East & North Africa |
| 150 | Angola | Sub-Saharan Africa |
| 200 | Antigua and Barbuda | America |
Utilice
.merge()para combinar el DataFrame co2 con el DataFrame df_gm. Esta función funciónmergebásicamente realiza una unión interna en los dos DataFrames (lo mismo como el inner join cuando se utiliza en bases de datos). Esta fusión es necesaria para garantizar que tanto el DataFrame co2 como el DataFrame gm estén formados por los mismos países, garantizando así que los valores de las emisiones de CO2 correspondan a sus respectivos países.how ='inner'Devuelve un marco de datos con sólo las filas que tienen características comunes. Una unión interna requiere que cada fila de los dos marcos de datos unidos tenga valores de columna que coincidan. Esto es similar a la intersección de dos conjuntos.
Outer Join or Full outer join: Manitene todas las filas de ambos marcos de datos, especifique
how='outer'Left Join or Left outer join: Para incluir todas las filas de su marco de datos \(x\) y sólo las de \(y\) que coincidan, especifique
how='left'.Right Join or Right outer join: Para incluir todas las filas de su marco de datos \(y\) y sólo las de \(x\) que coincidan, especifique
how='right'.

df_w_regions = pd.merge(co2, df_gm, left_on ='country', right_on ='Country', how ='inner')
df_w_regions.head()
| country | 1800 | 1801 | 1802 | 1803 | 1804 | 1805 | 1806 | 1807 | 1808 | ... | 2007 | 2008 | 2009 | 2010 | 2011 | 2012 | 2013 | 2014 | Country | region | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | Afghanistan | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | ... | 0.0854 | 0.154 | 0.242 | 0.294 | 0.412 | 0.35 | 0.316 | 0.299 | Afghanistan | South Asia |
| 1 | Albania | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | ... | 1.3000 | 1.460 | 1.480 | 1.560 | 1.790 | 1.68 | 1.730 | 1.960 | Albania | Europe & Central Asia |
| 2 | Algeria | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | ... | 3.1900 | 3.160 | 3.420 | 3.300 | 3.290 | 3.46 | 3.510 | 3.720 | Algeria | Middle East & North Africa |
| 3 | Angola | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | ... | 1.2000 | 1.180 | 1.230 | 1.240 | 1.250 | 1.33 | 1.250 | 1.290 | Angola | Sub-Saharan Africa |
| 4 | Antigua and Barbuda | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | ... | 5.1400 | 5.190 | 5.450 | 5.540 | 5.360 | 5.42 | 5.360 | 5.380 | Antigua and Barbuda | America |
5 rows × 218 columns
Elimina una de las columnas de países ya que hay dos:
df_w_regions = df_w_regions.drop('Country', axis='columns')
df_w_regions.head()
| country | 1800 | 1801 | 1802 | 1803 | 1804 | 1805 | 1806 | 1807 | 1808 | ... | 2006 | 2007 | 2008 | 2009 | 2010 | 2011 | 2012 | 2013 | 2014 | region | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | Afghanistan | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | ... | 0.0637 | 0.0854 | 0.154 | 0.242 | 0.294 | 0.412 | 0.35 | 0.316 | 0.299 | South Asia |
| 1 | Albania | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | ... | 1.2800 | 1.3000 | 1.460 | 1.480 | 1.560 | 1.790 | 1.68 | 1.730 | 1.960 | Europe & Central Asia |
| 2 | Algeria | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | ... | 2.9900 | 3.1900 | 3.160 | 3.420 | 3.300 | 3.290 | 3.46 | 3.510 | 3.720 | Middle East & North Africa |
| 3 | Angola | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | ... | 1.1000 | 1.2000 | 1.180 | 1.230 | 1.240 | 1.250 | 1.33 | 1.250 | 1.290 | Sub-Saharan Africa |
| 4 | Antigua and Barbuda | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | ... | 4.9100 | 5.1400 | 5.190 | 5.450 | 5.540 | 5.360 | 5.42 | 5.360 | 5.380 | America |
5 rows × 217 columns
A continuación, vamos a aplicar la función
.melt()a este DataFrame y a almacenarlo en un nuevo DataFrame llamado new_co2. Esta función cambia el formato de un DataFrame en uno que tenga variables identificadoras de nuestra elección. En nuestro caso queremos que las variables identificadoras sean país y región, ya que son las constantes. También vamos a cambiar el nombre de las columnas:
new_co2 = pd.melt(df_w_regions, id_vars=['country', 'region'])
new_co2.tail(10)
| country | region | variable | value | |
|---|---|---|---|---|
| 37185 | United Arab Emirates | Middle East & North Africa | 2014 | 23.300 |
| 37186 | United Kingdom | Europe & Central Asia | 2014 | 6.460 |
| 37187 | United States | America | 2014 | 16.500 |
| 37188 | Uruguay | America | 2014 | 1.970 |
| 37189 | Uzbekistan | Europe & Central Asia | 2014 | 3.450 |
| 37190 | Vanuatu | East Asia & Pacific | 2014 | 0.595 |
| 37191 | Venezuela | America | 2014 | 6.030 |
| 37192 | Vietnam | East Asia & Pacific | 2014 | 1.800 |
| 37193 | Zambia | Sub-Saharan Africa | 2014 | 0.288 |
| 37194 | Zimbabwe | Sub-Saharan Africa | 2014 | 0.780 |
columns = ['country', 'region', 'year', 'co2']
new_co2.columns = columns
new_co2.tail(10)
| country | region | year | co2 | |
|---|---|---|---|---|
| 37185 | United Arab Emirates | Middle East & North Africa | 2014 | 23.300 |
| 37186 | United Kingdom | Europe & Central Asia | 2014 | 6.460 |
| 37187 | United States | America | 2014 | 16.500 |
| 37188 | Uruguay | America | 2014 | 1.970 |
| 37189 | Uzbekistan | Europe & Central Asia | 2014 | 3.450 |
| 37190 | Vanuatu | East Asia & Pacific | 2014 | 0.595 |
| 37191 | Venezuela | America | 2014 | 6.030 |
| 37192 | Vietnam | East Asia & Pacific | 2014 | 1.800 |
| 37193 | Zambia | Sub-Saharan Africa | 2014 | 0.288 |
| 37194 | Zimbabwe | Sub-Saharan Africa | 2014 | 0.780 |
Establezca el límite inferior de la columna del año como 1964 para que la columna consista en valores int64 para 1964 y en adelante. Haga esto dentro del DataFrame new_co2 que creamos en el paso anterior, y almacénelo en un nuevo DataFrame llamado df_co2. Ordene los valores del DataFrame df_co2 por la columna del país y luego haga lo mismo con la columna del año utilizando .sort_values().
df_co2 = new_co2[new_co2['year'].astype('int64') > 1963]
df_co2 = df_co2.sort_values(by=['country', 'year'])
df_co2['year'] = df_co2['year'].astype('int64')
df_co2.head()
| country | region | year | co2 | |
|---|---|---|---|---|
| 28372 | Afghanistan | South Asia | 1964 | 0.0863 |
| 28545 | Afghanistan | South Asia | 1965 | 0.1010 |
| 28718 | Afghanistan | South Asia | 1966 | 0.1080 |
| 28891 | Afghanistan | South Asia | 1967 | 0.1240 |
| 29064 | Afghanistan | South Asia | 1968 | 0.1160 |
Ahora tenemos un DataFrame que consiste en las emisiones de dióxido de carbono por año y por país. Los números de serie no están en orden ascendente porque hemos ordenado los datos por la columna del país y luego por la del año. A continuación, vamos a crear una tabla similar para el PIB por año y por país.
Cree un nuevo DataFrame llamado df_gdp que conste de las columnas country, year y gdp del DataFrame gm
df_gdp = gm[['Country', 'Year', 'gdp']]
df_gdp.columns = ['country', 'year', 'gdp']
df_gdp.head()
| country | year | gdp | |
|---|---|---|---|
| 0 | Afghanistan | 1964 | 1182.0 |
| 1 | Afghanistan | 1965 | 1182.0 |
| 2 | Afghanistan | 1966 | 1168.0 |
| 3 | Afghanistan | 1967 | 1173.0 |
| 4 | Afghanistan | 1968 | 1187.0 |
Finalmente tenemos dos DataFrames que consisten en lo siguiente: Las emisiones de dióxido de carbono y el PIB. Combine los dos DataFrames utilizando la función .merge() en las columnas país y año. Guarde esto en un nuevo DataFrame llamado data. Utilice la función dropna() para eliminar los valores NaN
data = pd.merge(df_co2, df_gdp, on=['country', 'year'], how='left')
data = data.dropna()
data.head()
| country | region | year | co2 | gdp | |
|---|---|---|---|---|---|
| 0 | Afghanistan | South Asia | 1964 | 0.0863 | 1182.0 |
| 1 | Afghanistan | South Asia | 1965 | 0.1010 | 1182.0 |
| 2 | Afghanistan | South Asia | 1966 | 0.1080 | 1168.0 |
| 3 | Afghanistan | South Asia | 1967 | 0.1240 | 1173.0 |
| 4 | Afghanistan | South Asia | 1968 | 0.1160 | 1187.0 |
Por último, comprobemos la correlación entre las emisiones de dióxido de carbono y el PIB para asegurarnos de que estamos analizando datos que merecen ser visualizados. Crea un array
numpycon las columnas co2 y gdp:
np_co2 = np.array(data['co2'])
np_gdp = np.array(data['gdp'])
Utilice la función
.corrcoef()para imprimir la correlación entre las emisiones de y el PIB:
np.corrcoef(np_co2, np_gdp)
array([[1. , 0.78219731],
[0.78219731, 1. ]])
Como se puede ver en el resultado anterior, hay una alta correlación entre las emisiones de dióxido de carbono y el PIB.
Ejercicio 23: Creación del gráfico estático base para una visualización de datos interactiva¶
En este ejercicio, vamos a crear un gráfico estático para nuestro conjunto de datos y a añadirle glifos circulares circulares. Los siguientes pasos te ayudarán con la solución:
Import the following:
curdocdebokeh.io: Esto devuelve el estado actual por defecto del documento/ gráfico.La figura de
bokeh.plotting: Esto crea la figura para el trazado.HoverTool, ColumnDataSource, CategoricalColorMapper y Slider de
bokeh.models: Son herramientas y métodos interactivos para mapear datos de pandas DataFrames a una fuente de datos para su trazado.Spectral6 de
bokeh.palettes: Una paleta de colores para la gráfica.widgetboxyrowdebokeh.layouts:widgetboxcrea una columna de herramientas predefinidas (incluyendo el zoom), mientras querowcrea una fila de objetos de diseñobokeh, lo que les obliga a tener el mismo sizing_mode:
from bokeh.io import curdoc, output_notebook
from bokeh.models import HoverTool, ColumnDataSource, CategoricalColorMapper, Slider, CustomJS
from bokeh.palettes import Spectral6
from bokeh.layouts import widgetbox, row
from ipywidgets import interact
from bokeh.io import push_notebook, show, output_notebook
from bokeh.layouts import column
from bokeh.plotting import Figure, output_file, show
Ejecute la función output_notebook() para cargar BokehJS. Esto es lo que permite que el que se muestre en el notebook:
Vamos a codificar por colores nuestros puntos de datos (que serán los países individuales) en función de la región a la que pertenecen. Para ello, cree una lista de regiones aplicando la función .unique() a la columna región del DataFrame. Haga que una lista utilizando el método .tolist():
regions_list = data.region.unique().tolist()
Utilice CategoricalColorMapper para asignar un color del paquete Spectral6 a las diferentes regiones presentes en la lista regions_list:
color_mapper = CategoricalColorMapper(factors=regions_list, palette=Spectral6)
Utilizando la función
ColumnDataSourceconstruimos un diccionaro con las variables utlizadas en la grafica el cual llamaremos source_init. También crearemos otro que utlizaremos para actualizar la figura no estática por año la cual llamamos source_last
source_init = ColumnDataSource(data={'x': data.gdp[data.year == min(data.year)],
'y': data.co2[data.year == min(data.year)],
'country': data.country[data.year == min(data.year)],
'region': data.region[data.year == min(data.year)],
'year': data.year[data.year == min(data.year)]})
source_last = ColumnDataSource(data={'x': data.gdp, 'y': data.co2, 'year': data.year})
Creamos la figura vacía:
Establece el título como Emisiones de CO2 versus PIB en 1964
Establece el rango del eje x de xmin a xmax
Establece el rango del eje y desde ymin hasta ymax
Establezca el tipo de eje y como logarítmico
plot = Figure(title='CO2 Emissions vs GDP in 1964', y_axis_type='log')
Añadimos glifos circulares a la gráfica:
plot.circle(x='x', y='y',
fill_alpha=0.8,
source=source_init,
legend_label='region',
color=dict(field='region', transform=color_mapper),
size=7)
Establezca la ubicación de la leyenda en la esquina inferior derecha del gráfico, y agregue títulos a los ejes
plot.legend.location = 'bottom_right'
plot.xaxis.axis_label = 'Income Per Person'
plot.yaxis.axis_label = 'CO2 Emissions (tons per person)'
Ejercicio 24: Añadir una herramienta Hover¶
En este ejercicio, vamos a permitir que el usuario pase por encima de un punto de datos en nuestro gráfico para ver el nombre del país, las emisiones de dióxido de carbono y el PIB. Los siguientes pasos te ayudarán con la solución:
Crear una herramienta de rastreo llamada hover. Añade la herramienta hover a la gráfica
hover = HoverTool(tooltips=[('Country', '@country'), ('GDP', '@x'), ('CO2 Emission', '@y')])
plot.add_tools(hover)
show(plot)
Ejercicio 24: Añadir un deslizador al gráfico estático¶
Nombramos el archivo HTML de salida como co2_emissions
output_file("co2_emissions.html")
Creamos la función callback usando
CustomJSde la libreriabokehla cual permitira actualizar nuestra figura. Usamos algunas pocas ordenes en lenguajeJavaScript.
callback = CustomJS(args=dict(source_last=source_last, source_init=source_init), code="""
var data_init = source_init.data;
var yr = cb_obj.value;
var year = source_last.data['year'];
var x_new = [];
var y_new = [];
for(var i = 0; i < year.length; i++) {
if(year[i] == yr) {
x_new.push(source_last.data['x'][i]);
y_new.push(source_last.data['y'][i]);
}
}
data_init['x'] = x_new;
data_init['y'] = y_new;
source_init.change.emit();
""")
Construimos el slider que utlizaremos para actualizar las figuras, y realizamos el llamado de la función callback que recibirá como input cada año que proviende del slider
slider = Slider(start=min(data.year), end=max(data.year), step=1, value=min(data.year), title='Year')
slider.js_on_change('value', callback)
layout = column(slider, plot)
show(layout)
Como puede ver, en la esquina derecha, hay varias herramientas. Estas son generadas automáticamente por Bokeh cuando se crea un gráfico

Estas herramientas son las siguientes:
Pan: La herramienta de desplazamiento le permite mover y cambiar la vista de su parcela
Box Zoom: Le permite ampliar una sección cuadrada concreta de la cuadrado de la parcela
Wheel Zoom: Le permite acercarse arbitrariamente a cualquier punto del gráfico.
Save Plot: Permite guardar el gráfico actual.
Reset: Esto restablece el gráfico y le lleva de vuelta al gráfico original en el que aterrizó. a la parcela original.
Hover: Creamos una herramienta de hover en nuestra parcela y la programamos para que muestre cierta información. Sin embargo, Bokeh también genera automáticamente una herramienta hover que puede ser activada y desactivada por este icono. Esta herramienta puede no mostrar siempre lo que que queremos, por lo que hemos creado una nosotros mismos.
Visualización interactiva de datos con Plotly Express¶
Plotly es una biblioteca de Python muy popular y se utiliza para crear sorprendentes e informativas visualizaciones de datos interactivos.
Es una herramienta de ploteo basada en JSON, por lo que cada ploteo está definido por dos objetos JSON - datos y diseño.
El despliegue de una visualización Plotly requiere un poco más de esfuerzo que una visualización Bokeh porque tenemos que construir una aplicación separada (más comúnmente una aplicación Flask) utilizando el marco Dash.
En comparación con Bokeh, las herramientas y la sintaxis de Plotly son mucho más sencillas. Sin embargo, el código que se requiere para crear estas visualizaciones de datos interactivos es un poco más extenso.
Ejercicio 26: Creación de un gráfico de dispersión interactivo¶
En este ejercicio, vamos a crear una visualización de datos interactiva del DataFrame que creamos en el ejercicio anterior, de las emisiones de dióxido de carbono y el PIB. Los siguientes pasos te ayudarán con la solución
Abra un nuevo cuaderno Jupyter. Importe las siguientes bibliotecas y paquetes:
pandas: Para preparar el DataFrameplotly.express: Para crear las gráficas
import pandas as pd
import plotly.express as px
Cree el DataFrame de emisiones de dióxido de carbono y PIB del ejercicio anterior en este notebook:
url_co2 = 'https://raw.githubusercontent.com/lihkir/Uninorte/main/AppliedStatisticMS/DataVisualizationRPython/Lectures/Python/PythonDataSets/co2.csv'
co2 = pd.read_csv(url_co2)
url_gm = 'https://raw.githubusercontent.com/lihkir/Uninorte/main/AppliedStatisticMS/DataVisualizationRPython/Lectures/Python/PythonDataSets/gapminder.csv'
gm = pd.read_csv(url_gm)
df_gm = gm[['Country', 'region']].drop_duplicates()
df_w_regions = pd.merge(co2, df_gm, left_on='country', right_on='Country', how='inner')
df_w_regions = df_w_regions.drop('Country', axis='columns')
new_co2 = pd.melt(df_w_regions, id_vars=['country', 'region'])
columns = ['country', 'region', 'year', 'co2']
new_co2.columns = columns
df_co2 = new_co2[new_co2['year'].astype('int64') > 1963]
df_co2 = df_co2.sort_values(by=['country', 'year'])
df_co2['year'] = df_co2['year'].astype('int64')
df_gdp = gm[['Country', 'Year', 'gdp']]
df_gdp.columns = ['country', 'year', 'gdp']
data = pd.merge(df_co2, df_gdp, on=['country', 'year'], how='left')
data = data.dropna()
data.head()
| country | region | year | co2 | gdp | |
|---|---|---|---|---|---|
| 0 | Afghanistan | South Asia | 1964 | 0.0863 | 1182.0 |
| 1 | Afghanistan | South Asia | 1965 | 0.1010 | 1182.0 |
| 2 | Afghanistan | South Asia | 1966 | 0.1080 | 1168.0 |
| 3 | Afghanistan | South Asia | 1967 | 0.1240 | 1173.0 |
| 4 | Afghanistan | South Asia | 1968 | 0.1160 | 1187.0 |
Guarda los valores mínimo y máximo del PIB como xmin y xmax respectivamente
xmin, xmax = min(data.gdp), max(data.gdp)
Repita el paso 4 para los valores mínimos y máximos de emisión de dióxido de carbono
ymin, ymax = min(data.co2), max(data.co2)
Crea el gráfico de dispersión y guárdalo como fig:
El parámetro data será el nombre de nuestro DataFrame, es decir, data.
Asigna la columna gdp al eje x.
Asigna la columna co2 al eje y.
Establecer el parámetro animation_frame como la columna del año.
Establezca el parámetro animation_group como la columna del país.
Establezca el color de los puntos de datos como la columna región.
Asigna la columna country al parámetro hover_name.
Establecer el parámetro facet_col como la columna región (esto divide nuestro gráfico en seis columnas, una para cada región).
Establece la anchura como 1579 y la altura como 400.
El eje x debe ser logarítmico.
Establezca el parámetro size_max como 45.
Asigna el rango del eje x y del eje y como xmin, xmax y ymin, ymax, respectivamente
fig = px.scatter(data,
x="gdp", y="co2",
animation_frame="year",
animation_group="country",
color="region",
hover_name="country",
facet_col="region",
width=1579, height=400,
log_x=True,
size_max=45,
range_x=[xmin,xmax],
range_y=[ymin,ymax])
fig.show()
Observaciones
Como puede ver, tenemos un gráfico con seis subplots; uno para cada región.
Cada región está codificada por colores.
Cada subgrupo tiene las emisiones de dióxido de carbono en toneladas por persona como eje y la renta por persona en el eje de abscisas.
En la parte inferior del gráfico hay un control deslizante que nos permite comparar la correlación entre las emisiones de dióxido de carbono y la renta por año entre regiones y países por año.
Al pulsar el botón de reproducción en la esquina inferior izquierda, el gráfico progresa automáticamente desde el año 1964 hasta el 2013, mostrándonos cómo los puntos de datos con el tiempo.
También podemos mover manualmente el deslizador
Además, podemos pasar el ratón por encima de un punto de datos para obtener más información sobre él
Como puede ver, la creación de una visualización de datos interactivos con Plotly Express toma muy pocas líneas de código y la sintaxis es fácil de aprender y utilizar. Además de los gráficos de dispersión, la biblioteca biblioteca tiene muchos otros tipos de gráficos que puede utilizar para visualizar interactivamente diferentes tipos de datos los cuales serán estudiandos en las siguientes actividades.
Haga clic en el siguiente enlace para consultar otras gráficas disponibles con:
Plotly Express
Tarea 1.3¶
En esta actividad, trabajará con el mismo conjunto de datos que trabajó en los ejercicios de este capítulo. Es importante que pruebes varios tipos de visualización para para determinar la visualización que mejor transmite el mensaje que está tratando de dar con sus datos. Vamos a crear algunas visualizaciones interactivas utilizando la biblioteca
Plotly Expresspara determinar cuál es la que mejor se adapta a nuestros datos.Vuelve a crear el DataFrame de las emisiones de dióxido de carbono y del PIB.
Crea un gráfico de dispersión con los ejes x e y como year y co2 respectivamente. Añada un para los valores de co2 con el parámetro marginaly_y.
Crea un gráfico de caja para los valores del PIB con el parámetro marginal_x. Añada los parámetros de parámetros de animación en la columna del año
Crea un gráfico de dispersión con los ejes x e y como gdp y co2 respectivamente.
Cree un contorno de densidad con los ejes x e y como pib y co2 respectivamente.
Resumen
En este capítulo, hemos aprendido que las visualizaciones de datos interactivas están un paso por delante de las de las visualizaciones de datos estáticas debido a su capacidad para responder a las entradas humanas en tiempo real.
La gama de aplicaciones de las visualizaciones de datos interactivas es muy amplia, y podemos visualizar casi cualquier tipo de datos de forma interactiva.
Las entradas humanas que pueden incorporarse a las visualizaciones de datos interactivas incluyen, pero no se limitan a los controles deslizantes, las funciones de zoom, las herramientas de desplazamiento y los parámetros en los que se puede hacer clic.
BokehyPlotly Expressson dos de las bibliotecas dePythonmás populares y sencillas para crear visualizaciones de datos interactivas.En la proxima sección, veremos cómo crear hermosas visualizaciones de datos interactivas basadas en el contexto.
Visualización de datos a través de estratos¶
Objetivos
Crear interactividad en los gráficos de dispersión utilizando altair
Utilizar el zoom in y out, hover y tooltip, y seleccionar y resaltar en los gráficos de dispersión
Crear gráficos de barras y mapas de calor interactivos
Crear enlaces dinámicos entre diferentes tipos de gráficos dentro de una única visualización interactiva
En este capítulo, aprenderá a crear visualizaciones interactivas para datos estratificados con respecto a cualquier variable categórica.
Introducción¶
Una observación hecha en la sección anterior fue que cuando cuando se trata de introducir interactividad en ciertos tipos de gráficos de Python,
plotlypuede a veces ser verboso, y puede implicar una curva de aprendizaje empinada. Por lo tanto, en este capítulo, presentaremosaltair, una biblioteca diseñada especialmente para generar gráficos interactivos. - Demostraremos cómo crear visualizaciones interactivas conaltairpara datos estratificados con respecto a cualquier variable categórica. A modo de ilustración, utilizaremos un conjunto de datos para generar gráficos de dispersión y de barras con las características del conjunto de datos y añadir una variedad de elementos interactivos a los gráficos. También conoceremos algunas ventajas específicas del uso dealtairsobre una biblioteca más polivalente comoplotly.Utilizaremos el conjunto de datos del Índice de Felicidad Planetaria (IPH) http://happyplanetindex.org/ a lo largo de esta sección. Este conjunto de datos muestra en qué lugares del mundo la gente utiliza recursos ecológicos de forma más eficiente para vivir una vida larga y feliz. No sólo es un recurso interesante para conocer mejor las condiciones ecológicas y el bienestar socioeconómico de bienestar socioeconómico en varias partes de nuestro planeta, sino que también tiene una interesante mezcla de características que nos ayudan a demostrar ciertos conceptos clave de la visualización interactiva.
Gráficos de dispersión interactivos¶
Como ya sabe, los gráficos de dispersión son uno de los tipos de gráficos más esenciales para presentar patrones globales dentro de un conjunto de datos. Naturalmente, es importante saber cómo introducir la interactividad en estos gráficos. En primer lugar, veremos las acciones de zoom y restablecimiento de los gráficos. Antes de eso, sin embargo, vamos a echar un vistazo al conjunto de datos. Podemos ver el conjunto de datos del IPH utilizando el siguiente código
import pandas as pd
hpi_url = "https://raw.githubusercontent.com/lihkir/Uninorte/main/AppliedStatisticMS/DataVisualizationRPython/Lectures/Python/PythonDataSets/hpi_data_countries.tsv"
hpi_df = pd.read_csv(hpi_url, sep='\t')
hpi_df.head()
| HPI Rank | Country | Region | Life Expectancy (years) | Wellbeing (0-10) | Inequality of outcomes | Ecological Footprint (gha/capita) | Happy Planet Index | |
|---|---|---|---|---|---|---|---|---|
| 0 | 1 | Costa Rica | Americas | 79.1 | 7.3 | 15% | 2.8 | 44.7 |
| 1 | 2 | Mexico | Americas | 76.4 | 7.3 | 19% | 2.9 | 40.7 |
| 2 | 3 | Colombia | Americas | 73.7 | 6.4 | 24% | 1.9 | 40.7 |
| 3 | 4 | Vanuatu | Asia Pacific | 71.3 | 6.5 | 22% | 1.9 | 40.6 |
| 4 | 5 | Vietnam | Asia Pacific | 75.5 | 5.5 | 19% | 1.7 | 40.3 |
Tenga en cuenta que hay 5 características numéricas/cuantitativas en este conjunto de datos:
Life Expectancy (years)
Wellbeing (0-10)
Inequality of outcomes
Ecological Footprint (gha/capita)
Happy Planet Index
Hay dos características categóricas/nominales: Country y Region. En
altairlos rasgos cuantitativos se denotan como Q, y los rasgos nominales se denotan como N. Veremos pronto cómo utilizar esto en nuestras visualizaciones.Generemos y observemos un gráfico de dispersión estático, mediante un ejercicio, de las caracteristicas Wellbeing (0-10) and Happy Planet Index para cada país, utilizando diferentes colores para denotar la región a la que pertenece el país y seguir adelante y añadirle interactividad.
Ejercicio 27: Añadir Zoom-In y Zoom-Out a un gráfico de dispersión estático¶
En este ejercicio, generaremos un gráfico de dispersión estático utilizando
matplotlib. Utilizaremos el conjunto de datos hpi_data_countries para el gráfico y analizaremos las puntuaciones de Wellbeing de cada país representado por la leyenda del gráfico. Seguiremos adelante y añadiremos una función dezoom. Para ello utilizaremos la bibliotecaaltair.
Cargar el conjunto de datos hpi y leer desde el conjunto de datos usando pandas:
import pandas as pd
hpi_url = "https://raw.githubusercontent.com/lihkir/Uninorte/main/AppliedStatisticMS/DataVisualizationRPython/Lectures/Python/PythonDataSets/hpi_data_countries.tsv"
hpi_df = pd.read_csv(hpi_url, sep='\t')
Trazar un gráfico de dispersión estático utilizando
matplotlib
import seaborn as sns
import matplotlib.pyplot as plt
fig = plt.figure()
ax = fig.add_subplot(111)
ax = sns.scatterplot(x='Wellbeing (0-10)', y='Happy Planet Index', hue='Region', data=hpi_df)
plt.show()
Cada punto representa un país de una de las 7 regiones. El Wellbeing y el Happy Planet Index parecen estar correlacionados. Vemos una tendencia en las puntuaciones del Happy Planet Index y las puntuaciones de Wellbeing de las distintas regiones. Ahora que tenemos un gráfico de dispersión estático, vamos a explorar la interactividad de este gráfico. Veremos cómo hacer
zoom inyzoom out.
Importa el módulo
altaircomoalt. Antes debe instalaraltairusandopip install altair vega_datasets. En versiones anteriores de notebook (<5.3) es necesario habilitar adicionalmente la extensión:jupyter nbextension install --sys-prefix --py vega
import altair as alt
Proporcione el DataFrame elegido (hpi_df en nuestro caso) a la función
altair Chart. Utilice la funciónmark_circle()para denotar puntos de datos en el gráfico de dispersión utilizando círculos rellenos.Utilice la función
encodepara especificar las características en los ejes \(x\) e \(y\). Aunque también usamos el parámetro decoloren esta función para color-code los puntos de datos usando la característica de la región, esto es opcional. Por último, añada la funcióninteractive()para que el gráfico sea interactivo parazooming
alt.Chart(hpi_df).mark_circle().encode(
x='Wellbeing (0-10):Q',
y='Happy Planet Index:Q',
color='Region:N',).interactive()
¿Se ha dado cuenta de que hemos añadido un sufijo: Q junto a nuestras características cuantitativas y un sufijo: N junto a nuestras características nominales? Añadir sufijos como éste ayuda a altair a conocer el tipo de antemano, en lugar de tener que inferirlo por sí mismo.
Puede intentar eliminar los sufijos en este gráfico y verá que el gráfico se sigue generando sin errores porque altair puede adivinar el tipo de característica en este caso. Es una buena práctica incluir los sufijos ya que hay casos en los que
altairno puede inferir el tipo de característica.Los diversos parámetros, como \(x\), y \(y\) el color, que especificamos en la función de codificación son llamados canales en
altair.
Ejercicio 28: Añadir la funcionalidad Hover y Tooltip a un gráfico de dispersión¶
Cargar el conjunto de datos hpi y leer desde el conjunto de datos usando pandas:
import pandas as pd
hpi_url = "https://raw.githubusercontent.com/lihkir/Uninorte/main/AppliedStatisticMS/DataVisualizationRPython/Lectures/Python/PythonDataSets/hpi_data_countries.tsv"
hpi_df = pd.read_csv(hpi_url, sep='\t')
Importa el módulo
altaircomoalt
import altair as alt
Proporcione el
DataFrameelegido (hpi_dfen nuestro caso) a la funciónaltair Chartdealtair. Utilice la funciónmark_circle()para indicar los puntos de datos en el gráfico de dispersión de dispersión mediante círculos rellenos. Utilice la función encode para especificar las características en los ejes \(x\) y \(y\). Aunque utilizamos el parámetro decoloren esta función para codificar en color los puntos de datos utilizando la característica de región, esto es opcional.
alt.Chart(hpi_df).mark_circle().encode(
x = 'Wellbeing (0-10):Q',
y = 'Happy Planet Index:Q',
color = 'Region:N',
tooltip = ['Country', 'Region', 'Wellbeing (0-10)', 'Happy Planet Index', 'Life Expectancy (years)']
)
En el gráfico anterior, verá que las características mencionadas en el parámetro “tooltip” de la función de codificación se muestran cuando el cuando el cursor se acerca a cualquier punto de datos. Sin embargo, la función de zoom se ha perdido. ¿Cómo puede recuperarla? Muy sencillo: ¡añada la función
interactive()!Añade la función
interactive()para recuperar la función dezoomen el gráfico como como se muestra aquí
alt.Chart(hpi_df).mark_circle().encode(
x = 'Wellbeing (0-10):Q',
y = 'Happy Planet Index:Q',
color = 'Region:N',
tooltip = ['Country', 'Region', 'Wellbeing (0-10)', 'Happy Planet Index', 'Life Expectancy (years)']
).interactive()
Consideremos ahora un escenario más interesante. Supongamos que queremos seleccionar un área en el gráfico para examinar los puntos de datos dentro de ella
Ejercicio 29: Explorar la funcionalidad de seleccionar y resaltar en un gráfico de dispersión¶
En este ejercicio, vamos a utilizar la funcionalidad de seleccionar y resaltar utilizando
altair. Nosotros podemos hacer esto usando una función llamadaadd_selection. Primero tenemos que definir una variable que almacenará un intervalo de selección y luego generar el gráfico al que queremos añadir la función de selección. En el gráfico resultante, podemos hacer clic y luego arrastrar el cursor para crear un área de selección, que se coloreará de gris. Sigamos los siguientes pasos para hacerlo
Cargar el conjunto de datos hpi y leer desde el conjunto de datos usando pandas:
import pandas as pd
hpi_url = "https://raw.githubusercontent.com/lihkir/Uninorte/main/AppliedStatisticMS/DataVisualizationRPython/Lectures/Python/PythonDataSets/hpi_data_countries.tsv"
hpi_df = pd.read_csv(hpi_url, sep='\t')
Importa el módulo
altaircomoalt
import altair as alt
Defina la variable
selected_areapara almacenar el intervalo de selección
selected_area = alt.selection_interval()
Proporcione el
DataFrameelegido (hpi_dfen nuestro caso) a la funciónaltair ChartdealtairUtilice la función
mark_circle()para denotar puntos de datos en el gráfico de dispersión utilizando círculos rellenos. Utilice la funciónencodepara especificar las características en los ejes \(x\) e y \(y\). Aunque hemos utilizado el parámetro de color en esta función para colorear los puntos de datos utilizando la característica de región, esto es opcional. Utilice la funciónadd_selection()para especificar el área seleccionada
alt.Chart(hpi_df).mark_circle().encode(
x = 'Wellbeing (0-10):Q',
y = 'Happy Planet Index:Q',
color = 'Region:N'
).add_selection(
selected_area
)
Añade
alt_valuecomolightgraypara que todos los puntos fuera de la selección sean grises
selected_area = alt.selection_interval()
alt.Chart(hpi_df).mark_circle().encode(
x = 'Wellbeing (0-10):Q',
y = 'Happy Planet Index:Q',
color = alt.condition(selected_area, 'Region:N', alt.value('lightgray'))
).add_selection(
selected_area
)
Establecemos el parámetro de
coloren la función de codificación a una condición dealtairque retiene los colores de sólo los puntos dentro del área seleccionada. Esto puede ser útil cuando se desea obtener información sobre un rango particular de características en los ejes de un gráfico de dispersión.
Ejercicio 30: Generación de un trazado con las funciones de selección, zoom y hover/hoja de cálculo¶
En este ejercicio, seguiremos trabajando con el conjunto de datos del Happy Planet Index. La tarea de tarea consiste en crear un gráfico de dispersión para Well-being vs Happy Planet Index y hacer
zoomen el área con un alto Well-being y un alto Happy Planet index. Tendrá que determinar qué región predomina en el área de selección y, a continuación, enumerar los países de la zona. Sigamos los siguientes pasos:
Cargar el conjunto de datos hpi y leer desde el conjunto de datos usando pandas:
import pandas as pd
hpi_url = "https://raw.githubusercontent.com/lihkir/Uninorte/main/AppliedStatisticMS/DataVisualizationRPython/Lectures/Python/PythonDataSets/hpi_data_countries.tsv"
hpi_df = pd.read_csv(hpi_url, sep='\t')
Importa el módulo
altaircomoalt
import altair as alt
Cree un gráfico de dispersión de
altairpara Wellbeing vs Happy Planet Index junto con la función dezoom, utilizando la funcióninteractive(), y haz unzoomen el área que incluye el conjunto de puntos de datos en la parte superior derecha
alt.Chart(hpi_df).mark_circle().encode(
x = 'Wellbeing (0-10):Q',
y = 'Happy Planet Index:Q',
color = 'Region:N'
).interactive()
Ahora añada la característica de selección cambiando el parámetro de
colorpara incluir la condición de selección dealtair
selected_area = alt.selection_interval()
alt.Chart(hpi_df).mark_circle().encode(
x = 'Wellbeing (0-10):Q',
y = 'Happy Planet Index:Q',
color = alt.condition(selected_area, 'Region:N', alt.value('lightgray'))
).interactive().add_selection(
selected_area
)
Obsérvese que la mayoría de los países de la zona de selección (arriba a la derecha) pertenecen a América (de color azul). ¿Esperabas esto basándote en tus conocimientos generales? Añadamos la función para saber qué países aparecen en nuestra área de interés.
Añade la función
tooltippara localizar el área de interés
selected_area = alt.selection_interval()
alt.Chart(hpi_df).mark_circle().encode(
x = 'Wellbeing (0-10):Q',
y = 'Happy Planet Index:Q',
color=alt.condition(selected_area, 'Region:N', alt.value('lightgray')),
tooltip= ['Country', 'Region', 'Wellbeing (0-10)',
'Happy Planet Index', 'Life Expectancy (years)']
).interactive().add_selection(
selected_area
)
Si pasa el ratón por encima de la zona de interés, verá que los principales países son Costa Rica, México, Panamá y Colombia. Ahora, pasemos a la siguiente sección para observar cómo se puede utilizar la función de selección a través de múltiples figuras.
Ejercicio 31: Selección a través de múltiples parcelas¶
La función de selección puede ser mucho más potente cuando se vincula a varios gráficos. Consideraremos el ejemplo de dos gráficos de dispersión:
wellbeing vs happy planet index
life expectancy vs happy planet index
En este ejercicio, vamos a ir paso a paso para generar un gráfico interactivo. Para nuestro primer gráfico de dispersión, ya que queremos que el eje y sea común en ambos gráficos, especificaremos sólo el eje \(y\) en la función de codificación de nuestro gráfico de
altair, y luego añadiremos las características del eje \(x\) por separado en el objetoChart. Además, para poner los dos gráficos uno detrás de otro y permitir la selección entre ellos, utilizaremos la funciónaltairvconcat
Cargar el conjunto de datos hpi y leer desde el conjunto de datos usando pandas:
import pandas as pd
hpi_url = "https://raw.githubusercontent.com/lihkir/Uninorte/main/AppliedStatisticMS/DataVisualizationRPython/Lectures/Python/PythonDataSets/hpi_data_countries.tsv"
hpi_df = pd.read_csv(hpi_url, sep='\t')
Importa el módulo
altaircomoalt
import altair as alt
Trace el gráfico de dispersión con la función
Chart altair vconcatpara colocar dos gráficos verticalmente uno tras otro
chart = alt.Chart(hpi_df).mark_circle().encode(
y='Happy Planet Index',
color='Region:N'
)
chart1 = chart.encode(x = 'Wellbeing (0-10)')
chart2 = chart.encode(x = 'Life Expectancy (years)')
alt.vconcat(chart1, chart2)
Por cierto, existen atajos para las funciones
hconcatyvconcat. Podemos sustituiralt.hconcat(chart1, chart2)porchart1 | chart2yalt.vconcat(chart1, chart2)porchart1 & chart2Añade las funciones
hoverytooltipque enlazan los dos gráficos utilizando el siguiente código
# hover and tooltip across multiple charts
selected_area = alt.selection_interval()
chart = alt.Chart(hpi_df).mark_circle().encode(
y = 'Happy Planet Index',
color=alt.condition(selected_area, 'Region', alt.value('lightgray'))
).add_selection(
selected_area
)
chart1 = chart.encode(x = 'Wellbeing (0-10)')
chart2 = chart.encode(x = 'Life Expectancy (years)')
chart1 | chart2
Intente seleccionar un área en cualquiera de las gráficas. Observará que la selección en un gráfico automáticamente lleva a resaltar los mismos puntos de datos en el otro gráfico.
Ejercicio 32: Selección basada en los valores de una característica¶
En este ejercicio, crearemos un gráfico interactivo donde podremos ver los puntos de datos en función de una Region determinada. Utilizaremos la función
selection_single()para obtener un conjunto seleccionado de puntos de datos. Si se estudia el código con atención, se verá que los parámetros de esta función se explican por sí mismos. Para cualquier aclaración, por favor lea sobre ellos en la documentación oficial en https://altair-viz.github.io/user_guide/generated/api/altair.selection_single.html.
Importe los módulos de Python necesarios
import altair as alt
import pandas as pd
Lectura del conjunto de datos:
hpi_url = "https://raw.githubusercontent.com/lihkir/Uninorte/main/AppliedStatisticMS/DataVisualizationRPython/Lectures/Python/PythonDataSets/hpi_data_countries.tsv"
hpi_df = pd.read_csv(hpi_url, sep='\t')
Cree una variable
input_dropdownutilizando la funciónbinding_select()y establezca el parámetro options en la lista de regiones de nuestro conjunto de datos. Utilice la funciónselection_single()para seleccionar un conjunto de puntos de datos. Utilice la variable de color para almacenar la condición bajo la cual se seleccionarán los puntos de dato
input_dropdown = alt.binding_select(options = list(set(hpi_df.Region)))
selected_points = alt.selection_single(fields = ['Region'], bind = input_dropdown, name = 'Select')
color = alt.condition(selected_points,
alt.Color('Region:N'),
alt.value('lightgray'))
alt.Chart(hpi_df).mark_circle().encode(
x = 'Wellbeing (0-10):Q',
y = 'Happy Planet Index:Q',
color = color,
tooltip='Region:N'
).add_selection(
selected_points
)
El gráfico anterior tiene inicialmente todos sus puntos de datos en color. Sin embargo, al seleccionar un valor para la característica Region en el menú desplegable de entrada, observará que los correspondientes países están resaltados en color, mientras que todos los demás países están en gris. En los dos gráficos anteriores, el primero muestra los puntos de datos de la región de Americas y el segundo gráfico muestra los puntos de datos de la región Post-communist.
Ahora que sabemos cómo añadir interactividad a los gráficos de dispersión, vamos a aprender a introducir la interactividad en otros dos tipos de visualización importantes: los gráficos de barras y los mapas de calor
Ejercicio 33: Añadir una función de Zoom-In/Zoom-Out y calcular la media en un gráfico de barras estático¶
En este ejercicio, primero generaremos un simple gráfico de barras (estático) y luego exploraremos la interactividad, como el acercamiento y el alejamiento. A continuación, utilizaremos el mismo gráfico de barras y averiguaremos la media del Happy Planet Index de cada región. Utilizaremos la biblioteca
altairy el conjunto de datos del Happy Planet Index
Importe los módulos de Python necesarios
import altair as alt
import pandas as pd
Lectura del conjunto de datos:
hpi_url = "https://raw.githubusercontent.com/lihkir/Uninorte/main/AppliedStatisticMS/DataVisualizationRPython/Lectures/Python/PythonDataSets/hpi_data_countries.tsv"
hpi_df = pd.read_csv(hpi_url, sep='\t')
Utilice la función
mark_bar()para señalar puntos de datos en el gráfico de barras. Utilice la función encode para especificar las características en los ejes \(x\) e \(y\)
mean(hpi_df['Happy Planet Index'])
# hpi_df.head()
26.407857142857146
alt.Chart(hpi_df).mark_bar().encode(
x='Region:N',
y='mean(Happy Planet Index):Q',
)
Sin embargo, el gráfico anterior parece demasiado estrecho. Podemos arreglar esto fácilmente estableciendo el anchura del gráfico a un valor diferente utilizando la función de propiedades. Establezca el ancho a 400 utilizando la función de propiedades para aumentar el ancho del gráfico de barras:
alt.Chart(hpi_df).mark_bar().encode(
x = 'Region:N',
y = 'mean(Happy Planet Index):Q'
).properties(width=400)
Utiliza la función
interactivepara zoom in/out:
import altair as alt
alt.Chart(hpi_df).mark_bar().encode(
x = 'Region:N',
y = alt.Y('Happy Planet Index')
).properties(width=400).interactive()
Utilice el operador | para mostrar la media del IPH en todas las regiones:
import altair as alt
bars = alt.Chart(hpi_df).mark_bar().encode(
x = 'Region:N',
y = 'mean(Happy Planet Index):Q'
).properties(width=400)
line = alt.Chart(hpi_df).mark_rule(color='firebrick').encode(
y = 'mean(Happy Planet Index):Q',
size = alt.SizeValue(3)
)
bars | line
No queremos que la línea se coloque junto a nuestro gráfico de barras. La queremos en el gráfico. Entonces, ¿cómo lo hacemos? Para ello, tenemos que utilizar el concepto de capa en
altair. La idea es crear variables para almacenar el gráfico de barras y el gráfico de líneas, y luego superponerlos uno encima del otro.Add the layer function from the
altairlibrary
import altair as alt
bars = alt.Chart().mark_bar().encode(
x = 'Region:N',
y = 'mean(Happy Planet Index):Q'
).properties(width=400)
line = alt.Chart().mark_rule(color='firebrick').encode(
y='mean(Happy Planet Index):Q',
size = alt.SizeValue(3)
)
alt.layer(bars, line, data=hpi_df)
Así pues, ahora sabemos que la media del Índice del Planeta Feliz en todas las regiones es de alrededor de 26. Además, también hay que tener en cuenta que no especificamos el conjunto de datos hasta que utilizamos la función de capa. Es decir, no proporcionamos el conjunto de datos hpi_df en la función
Chart()como es habitual. En su lugar, lo mencionamos en la función de capa con el parámetro data = hpi_df.Ahora que conoce el concepto de estratificación en
altair, puede confiar en un atajo para ello. Sólo tienes que escribir el código de forma independiente para diferentes parcelas, como lo harías normalmente, y luego utilizar el operador+, como se muestra en el siguiente ejemplo
Ejercicio 34: Un atajo alternativo para representar la media en un gráfico de barras¶
En este ejercicio, calcularemos la media del índice HPI en un gráfico de barras utilizando un del código utilizado en el Ejercicio 33, añadiendo cálculo de la media en un gráfico de barras estático.
import altair as alt
bars = alt.Chart(hpi_df).mark_bar().encode(
x = 'Region:N',
y = 'mean(Happy Planet Index):Q',
).properties(width=400)
line = alt.Chart(hpi_df).mark_rule(color = 'firebrick').encode(
y = 'mean(Happy Planet Index):Q',
size = alt.SizeValue(3)
)
bars + line
Utilice el mecanismo de clic y arrastre utilizando el siguiente código en
altair. Puede utilizar el mecanismo de clic y arrastre para seleccionar cualquier conjunto de barras y ver cómo la línea que indica la media del Happy Planet Index se desplaza en consecuencia.
import altair as alt
selected_bars = alt.selection(type = 'interval', encodings = ['x'])
bars = alt.Chart(hpi_df).mark_bar().encode(
x = 'Region:N',
y = 'mean(Happy Planet Index):Q',
opacity = alt.condition(selected_bars, alt.OpacityValue(1), alt.OpacityValue(0.7)),
).properties(width=400).add_selection(
selected_bars
)
line = alt.Chart(hpi_df).mark_rule(color = 'firebrick').encode(
y = 'mean(Happy Planet Index):Q',
size = alt.SizeValue(3)
).transform_filter(
selected_bars
)
bars + line
Ejercicio 35: Añadir una función de zoom en un mapa de calor estático¶
En este ejercicio, utilizaremos
altairpara crear un mapa de calor que indique el número de países con el IPH y el Wellbeing en varios rangos. A continuación, añadiremos la función de zoom al mapa. También añadiremos círculos en el mapa de calor para mostrar diferentes países.
Importe los módulos de Python necesarios
import altair as alt
import pandas as pd
Lectura del conjunto de datos:
hpi_url = "https://raw.githubusercontent.com/lihkir/Uninorte/main/AppliedStatisticMS/DataVisualizationRPython/Lectures/Python/PythonDataSets/hpi_data_countries.tsv"
hpi_df = pd.read_csv(hpi_url, sep='\t')
Proporcione el DataFrame elegido (hpi_df en nuestro caso) a la función
altair Chart. Utilice la funciónmark_rect()para indicar los puntos de datos en el gráfico de barras. Utilice la función encode para especificar las características en los ejes \(x\) e \(y\). Asigne a el parámetrobinen True para que ajuste automáticamente cadabin
alt.Chart(hpi_df).mark_rect().encode(
alt.X('Happy Planet Index:Q', bin=True),
alt.Y('Wellbeing (0-10):Q', bin=True),
alt.Color('count()', scale=alt.Scale(scheme='greenblue'), legend=alt.Legend(title='Total Countries'))
)
Utilice la función
interactivey añada la capacidad de zoom. Utilice el siguiente código
alt.Chart(hpi_df).mark_rect().encode(
alt.X('Happy Planet Index:Q', bin = True),
alt.Y('Wellbeing (0-10):Q', bin = True),
alt.Color('count()', scale = alt.Scale(scheme='greenblue'), legend = alt.Legend(title='Total Countries'))
).interactive()
Al igual que podemos utilizar una paleta de colores para indicar el número de países en cada celda del mapa de calor, también podemos dibujar círculos de distintos tamaños en un mapa de calor para indicar el número de países. Dibuja círculos en el mapa térmico utilizando la función heatmap+circles. Los distintos tamaños de los círculos indican el número de países con un rango de Wellbeing variable.
heatmap = alt.Chart(hpi_df).mark_rect().encode(
alt.X('Happy Planet Index:Q', bin=True),
alt.Y('Wellbeing (0-10):Q', bin=True)
)
circles = heatmap.mark_point().encode(
alt.ColorValue('lightgray'),
alt.Size('count()', legend=alt.Legend(title='Records in Selection'))
)
heatmap + circles
Ejercicio 36: Creación de un diagrama de barras y un mapa de calor contiguos¶
En este ejercicio, seguiremos trabajando con el conjunto de datos del IPH. El objetivo es dibujar un diagrama de barras que represente el número de países en cada región y un mapa de calor al lado, indicando el número de países en varios rangos de wellbeing y life-expectancy
Importe los módulos de Python necesarios
import altair as alt
import pandas as pd
Lectura del conjunto de datos:
hpi_url = "https://raw.githubusercontent.com/lihkir/Uninorte/main/AppliedStatisticMS/DataVisualizationRPython/Lectures/Python/PythonDataSets/hpi_data_countries.tsv"
hpi_df = pd.read_csv(hpi_url, sep='\t')
Genere el gráfico de barras requerido utilizando la función
mark_bar()
alt.Chart(hpi_df).mark_bar().encode(
x = 'Region:N',
y = 'count():Q'
).properties(width=350)
Genera el mapa de calor requerido utilizando la función
mark_rect()
alt.Chart(hpi_df).mark_rect().encode(
alt.X('Wellbeing (0-10):Q', bin = True),
alt.Y('Life Expectancy (years):Q', bin = True),
alt.Color('count()', scale=alt.Scale(scheme='greenblue'), legend=alt.Legend(title='Total Countries'))
).properties(width=350)
Combine el código para colocar el gráfico de barras y el mapa de calor uno al lado del otro utilizando la función
bars | heatmap
bars = alt.Chart(hpi_df).mark_bar().encode(
x = 'Region:N',
y = 'count():Q'
).properties(width=350)
heatmap = alt.Chart(hpi_df).mark_rect().encode(
alt.X('Wellbeing (0-10):Q', bin = True),
alt.Y('Life Expectancy (years):Q', bin = True),
alt.Color('count()', scale = alt.Scale(scheme = 'greenblue'), legend = alt.Legend(title = 'Total Countries'))
).properties(width=350)
bars | heatmap
Ejercicio 37: Vincular dinámicamente un gráfico de barras y un mapa de calor¶
En este ejercicio, enlazaremos un gráfico de barras y un mapa de calor de forma dinámica. Considere un escenario en el que desea poder hacer clic en cualquiera de las barras de un gráfico de barras y tener un mapa de calor correspondiente a la región representada por la barra. Así, por ejemplo, quiere actualizar el mapa térmico de la Life Expectancy frente al Well Being sólo para los países de una región determinada.
Importe los módulos de Python necesarios
import altair as alt
import pandas as pd
Lectura del conjunto de datos:
hpi_url = "https://raw.githubusercontent.com/lihkir/Uninorte/main/AppliedStatisticMS/DataVisualizationRPython/Lectures/Python/PythonDataSets/hpi_data_countries.tsv"
hpi_df = pd.read_csv(hpi_url, sep='\t')
hpi_df.head()
| HPI Rank | Country | Region | Life Expectancy (years) | Wellbeing (0-10) | Inequality of outcomes | Ecological Footprint (gha/capita) | Happy Planet Index | |
|---|---|---|---|---|---|---|---|---|
| 0 | 1 | Costa Rica | Americas | 79.1 | 7.3 | 15% | 2.8 | 44.7 |
| 1 | 2 | Mexico | Americas | 76.4 | 7.3 | 19% | 2.9 | 40.7 |
| 2 | 3 | Colombia | Americas | 73.7 | 6.4 | 24% | 1.9 | 40.7 |
| 3 | 4 | Vanuatu | Asia Pacific | 71.3 | 6.5 | 22% | 1.9 | 40.6 |
| 4 | 5 | Vietnam | Asia Pacific | 75.5 | 5.5 | 19% | 1.7 | 40.3 |
Seleccione la región mediante el método de
selection
selected_region = alt.selection(type="single", encodings=['x'])
heatmap = alt.Chart(hpi_df).mark_rect().encode(
alt.X('Wellbeing (0-10):Q', bin=True),
alt.Y('Life Expectancy (years):Q', bin=True),
alt.Color('count()', scale = alt.Scale(scheme = 'greenblue'), legend = alt.Legend(title = 'Total Countries'))
).properties(
width=350
)
Colocar los círculos en un mapa de calor
circles = heatmap.mark_point().encode(
alt.ColorValue('grey'),
alt.Size('count()', legend = alt.Legend(title='Records in Selection'))
).transform_filter(
selected_region
)
Utilice la función
heatmap+circles | barspara vincular dinámicamente el gráfico de barras y el mapa de calor
bars = alt.Chart(hpi_df).mark_bar().encode(
x = 'Region:N',
y = 'count()',
color = alt.condition(selected_region, alt.ColorValue("steelblue"), alt.ColorValue("grey"))
).properties(
width=350
).add_selection(selected_region)
heatmap + circles | bars
Al hacer clic en cada gráfico de barras, verás que la paleta de colores que indica el total de países en de bienestar y esperanza de vida permanece constante, mientras que los círculos los círculos se actualizan para reflejar el número de países en el rango correspondiente para la región seleccionada.
La galería de ejemplos en https://altair-viz.github.io/gallery/index.html le proporcionará con una comprensión aún más profunda de las posibilidades de visualización en
altair
En la sección anterior, presentamos una visión general de algunas formas importantes de añadir interactividad a los gráficos de barras y a los mapas de calor. En concreto, se ha aprendido
Cómo generar un gráfico de barras con la función
altairmark_bar()Cómo generar un mapa de calor utilizando la función
altair mark_rect(), y cómo utilizar paletas de colores y círculos para representar visualmente los datos del mapa de calorCómo añadir capacidades de zoom a los gráficos de barras y a los mapas de calor utilizando la función función
interactive()Cómo utilizar la capacidad de estratificación en
altairpara presentar gráficos uno encima del otro utilizando la funciónlayer()o el operador+Cómo enlazar dinámicamente gráficos de barras y mapas de calor para crear una única y atractiva visualización
Tarea 1.4¶
Trabajaremos con el conjunto de datos de Google Play Store Apps alojado en googleplaystore.csv. Su tarea es crear una visualización con:
Un gráfico de barras de un número de aplicaciones estratificado por cada categoría Content Rating (calificado por Everyone/Teen).
Un mapa de calor que indica el número de aplicaciones estratificadas por app Category y rangos de rangos segmentados por Rating. El usuario debe poder interactuar con el gráfico seleccionando cualquiera de los tipos de Content Rating y el cambio correspondiente debería reflejarse en el mapa de calor para incluir sólo el número de aplicaciones en la categoría Content Rating.
Pasos principales
Descargue el conjunto de datos googleplaystore.csv y formatéelo como un
pandasDataFrameElimina las entradas del
DataFrameque tienen valores de característica deNA.Cree el gráfico de barras necesario del número de aplicaciones en cada categoría Content Rating
Cree el mapa de calor necesario indicando el número de aplicaciones en la app en rangos Category y Rating
Combine el código del gráfico de barras y del mapa de calor y cree una visualización con ambos gráficos vinculados dinámicamente entre sí.
Interprete cada visualización
Algunas visualizaciones esperadas
df = pd.read_csv("https://raw.githubusercontent.com/lihkir/Uninorte/main/AppliedStatisticMS/DataVisualizationRPython/Lectures/Python/PythonDataSets/googleplaystore.csv")
df.head()
| App | Category | Rating | Reviews | Size | Installs | Type | Price | Content Rating | Genres | Last Updated | Current Ver | Android Ver | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | Photo Editor & Candy Camera & Grid & ScrapBook | ART_AND_DESIGN | 4.1 | 159 | 19M | 10,000+ | Free | 0 | Everyone | Art & Design | January 7, 2018 | 1.0.0 | 4.0.3 and up |
| 1 | Coloring book moana | ART_AND_DESIGN | 3.9 | 967 | 14M | 500,000+ | Free | 0 | Everyone | Art & Design;Pretend Play | January 15, 2018 | 2.0.0 | 4.0.3 and up |
| 2 | U Launcher Lite – FREE Live Cool Themes, Hide ... | ART_AND_DESIGN | 4.7 | 87510 | 8.7M | 5,000,000+ | Free | 0 | Everyone | Art & Design | August 1, 2018 | 1.2.4 | 4.0.3 and up |
| 3 | Sketch - Draw & Paint | ART_AND_DESIGN | 4.5 | 215644 | 25M | 50,000,000+ | Free | 0 | Teen | Art & Design | June 8, 2018 | Varies with device | 4.2 and up |
| 4 | Pixel Draw - Number Art Coloring Book | ART_AND_DESIGN | 4.3 | 967 | 2.8M | 100,000+ | Free | 0 | Everyone | Art & Design;Creativity | June 20, 2018 | 1.1 | 4.4 and up |
